]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/docview.py
Added docview modules from Peter Yared and Morgan Hua
[wxWidgets.git] / wxPython / wx / lib / docview.py
diff --git a/wxPython/wx/lib/docview.py b/wxPython/wx/lib/docview.py
new file mode 100644 (file)
index 0000000..8f5f038
--- /dev/null
@@ -0,0 +1,3033 @@
+#----------------------------------------------------------------------------
+# Name:         docview.py
+# Purpose:      Port of the wxWindows docview classes
+#
+# Author:       Peter Yared
+#
+# Created:      5/15/03
+# CVS-ID:       $Id$
+# Copyright:    (c) 2003-2004 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al)
+# License:      wxWindows license
+#----------------------------------------------------------------------------
+
+
+import os
+import os.path
+import wx
+import sys
+_ = wx.GetTranslation
+
+
+#----------------------------------------------------------------------
+# docview globals
+#----------------------------------------------------------------------
+
+DOC_SDI = 1
+DOC_MDI = 2
+DOC_NEW = 4
+DOC_SILENT = 8
+DOC_OPEN_ONCE = 16
+DEFAULT_DOCMAN_FLAGS = DOC_SDI & DOC_OPEN_ONCE
+
+TEMPLATE_VISIBLE = 1
+TEMPLATE_INVISIBLE = 2
+DEFAULT_TEMPLATE_FLAGS = TEMPLATE_VISIBLE
+
+MAX_FILE_HISTORY = 9
+
+
+#----------------------------------------------------------------------
+# Convenience functions from wxWindows used in docview
+#----------------------------------------------------------------------
+
+
+def FileNameFromPath(path):
+    """
+    Returns the filename for a full path.
+    """
+    return os.path.split(path)[1]
+
+def FindExtension(path):
+    """
+    Returns the extension of a filename for a full path.
+    """
+    return os.path.splitext(path)[1].lower()
+
+def FileExists(path):
+    """
+    Returns True if the path exists.
+    """
+    return os.path.isfile(path)
+
+def PathOnly(path):
+    """
+    Returns the path of a full path without the filename.
+    """
+    return os.path.split(path)[0]
+
+
+#----------------------------------------------------------------------
+# Document/View Classes
+#----------------------------------------------------------------------
+
+
+class Document(wx.EvtHandler):
+    """
+    The document class can be used to model an application's file-based data. It
+    is part of the document/view framework supported by wxWindows, and cooperates
+    with the wxView, wxDocTemplate and wxDocManager classes.
+    """
+
+
+    def __init__(self, parent = None):
+        """
+        Constructor.  Define your own default constructor to initialize
+        application-specific data.
+        """
+        wx.EvtHandler.__init__(self)
+
+        self._documentModified = False
+        self._documentParent = parent
+        self._documentTemplate = None
+        self._commandProcessor = None
+        self._savedYet = False
+
+        self._documentTitle = None
+        self._documentFile = None
+        self._documentTypeName = None
+        self._documentModified = False
+        self._documentViews = []
+
+
+    def ProcessEvent(self, event):
+        """
+        Processes an event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        return False
+
+
+    def GetFilename(self):
+        """
+        Gets the filename associated with this document, or "" if none is
+        associated.
+        """
+        return self._documentFile
+
+
+    def GetTitle(self):
+        """
+        Gets the title for this document. The document title is used for an
+        associated frame (if any), and is usually constructed by the framework
+        from the filename.
+        """
+        return self._documentTitle
+
+
+    def SetTitle(self, title):
+        """
+        Sets the title for this document. The document title is used for an
+        associated frame (if any), and is usually constructed by the framework
+        from the filename.
+        """
+        self._documentTitle = title
+
+
+    def GetDocumentName(self):
+        """
+        The document type name given to the wxDocTemplate constructor,
+        copied to this document when the document is created. If several
+        document templates are created that use the same document type, this
+        variable is used in wxDocManager::CreateView to collate a list of
+        alternative view types that can be used on this kind of document.
+        """
+        return self._documentTypeName
+
+
+    def SetDocumentName(self, name):
+        """
+        Sets he document type name given to the wxDocTemplate constructor,
+        copied to this document when the document is created. If several
+        document templates are created that use the same document type, this
+        variable is used in wxDocManager::CreateView to collate a list of
+        alternative view types that can be used on this kind of document. Do
+        not change the value of this variable.
+        """
+        self._documentTypeName = name
+
+
+    def GetDocumentSaved(self):
+        """
+        Returns True if the document has been saved.  This method has been
+        added to wxPython and is not in wxWindows.
+        """
+        return self._savedYet
+
+
+    def SetDocumentSaved(self, saved = True):
+        """
+        Sets whether the document has been saved.  This method has been
+        added to wxPython and is not in wxWindows.
+        """
+        self._savedYet = saved
+
+
+    def GetCommandProcessor(self):
+        """
+        Returns the command processor associated with this document.
+        """
+        return self._commandProcessor
+
+
+    def SetCommandProcessor(self, processor):
+        """
+        Sets the command processor to be used for this document. The document
+        will then be responsible for its deletion. Normally you should not
+        call this; override OnCreateCommandProcessor instead.
+        """
+        self._commandProcessor = processor
+
+
+    def IsModified(self):
+        """
+        Returns true if the document has been modified since the last save,
+        false otherwise. You may need to override this if your document view
+        maintains its own record of being modified (for example if using
+        wxTextWindow to view and edit the document).
+        """
+        return self._documentModified
+
+
+    def Modify(self, modify):
+        """
+        Call with true to mark the document as modified since the last save,
+        false otherwise. You may need to override this if your document view
+        maintains its own record of being modified (for example if using
+        xTextWindow to view and edit the document).
+        """
+        self._documentModified = modify
+
+
+    def GetViews(self):
+        """
+        Returns the list whose elements are the views on the document.
+        """
+        return self._documentViews
+
+
+    def GetDocumentTemplate(self):
+        """
+        Returns the template that created the document.
+        """
+        return self._documentTemplate
+
+
+    def SetDocumentTemplate(self, template):
+        """
+        Sets the template that created the document. Should only be called by
+        the framework.
+        """
+        self._documentTemplate = template
+
+
+    def DeleteContents(self):
+        """
+        Deletes the contents of the document.  Override this method as
+        necessary.
+        """
+        return True
+
+
+    def Destroy(self):
+        """
+        Destructor. Removes itself from the document manager.
+        """
+        self.DeleteContents()
+        if self.GetDocumentManager():
+            self.GetDocumentManager().RemoveDocument(self)
+        wx.EvtHandler.Destroy(self)
+
+
+    def Close(self):
+        """
+        Closes the document, by calling OnSaveModified and then (if this true)
+        OnCloseDocument. This does not normally delete the document object:
+        use DeleteAllViews to do this implicitly.
+        """
+        if self.OnSaveModified():
+            if self.OnCloseDocument():
+                return True
+            else:
+                return False
+        else:
+            return False
+
+
+    def OnCloseDocument(self):
+        """
+        The default implementation calls DeleteContents (an empty
+        implementation) sets the modified flag to false. Override this to
+        supply additional behaviour when the document is closed with Close.
+        """
+        self.NotifyClosing()
+        self.DeleteContents()
+        self.Modify(False)
+        return True
+
+
+    def DeleteAllViews(self):
+        """
+        Calls wxView.Close and deletes each view. Deleting the final view will
+        implicitly delete the document itself, because the wxView destructor
+        calls RemoveView. This in turns calls wxDocument::OnChangedViewList,
+        whose default implemention is to save and delete the document if no
+        views exist.
+        """
+        manager = self.GetDocumentManager()
+        for view in self._documentViews:
+            if not view.Close():
+                return False
+        if self in manager.GetDocuments():
+            self.Destroy()
+        return True
+
+
+    def GetFirstView(self):
+        """
+        A convenience function to get the first view for a document, because
+        in many cases a document will only have a single view.
+        """
+        if len(self._documentViews) == 0:
+            return None
+        return self._documentViews[0]
+
+
+    def GetDocumentManager(self):
+        """
+        Returns the associated document manager.
+        """
+        if self._documentTemplate:
+            return self._documentTemplate.GetDocumentManager()
+        return None
+
+
+    def OnNewDocument(self):
+        """
+        The default implementation calls OnSaveModified and DeleteContents,
+        makes a default title for the document, and notifies the views that
+        the filename (in fact, the title) has changed.
+        """
+        if not self.OnSaveModified() or not self.OnCloseDocument():
+            return False
+        self.DeleteContents()
+        self.Modify(False)
+        self.SetDocumentSaved(False)
+        name = self.GetDocumentManager().MakeDefaultName()
+        self.SetTitle(name)
+        self.SetFilename(name, notifyViews = True)
+
+
+    def Save(self):
+        """
+        Saves the document by calling OnSaveDocument if there is an associated
+        filename, or SaveAs if there is no filename.
+        """
+        if not self.IsModified() and self._savedYet:
+            return True
+
+        if not self._documentFile or not self._savedYet:
+            return self.SaveAs()
+        return self.OnSaveDocument(self._documentFile)
+
+
+    def SaveAs(self):
+        """
+        Prompts the user for a file to save to, and then calls OnSaveDocument.
+        """
+        docTemplate = self.GetDocumentTemplate()
+        if not docTemplate:
+            return False
+
+        descr = docTemplate.GetDescription() + _(" (") + docTemplate.GetFileFilter() + _(") |") + docTemplate.GetFileFilter()  # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
+        filename = wx.FileSelector(_("Save As"),
+                                   docTemplate.GetDirectory(),
+                                   FileNameFromPath(self.GetFilename()),
+                                   docTemplate.GetDefaultExtension(),
+                                   wildcard = descr,
+                                   flags = wx.SAVE | wx.OVERWRITE_PROMPT,
+                                   parent = self.GetDocumentWindow())
+        if filename == "":
+            return False
+
+        name, ext = os.path.splitext(filename)
+        if ext == "":
+            filename += '.' + docTemplate.GetDefaultExtension()
+
+        self.SetFilename(filename)
+        self.SetTitle(FileNameFromPath(filename))
+
+        for view in self._documentViews:
+            view.OnChangeFilename()
+
+        if not self.OnSaveDocument(filename):
+            return False
+
+        if docTemplate.FileMatchesTemplate(filename):
+            self.GetDocumentManager().AddFileToHistory(filename)
+            
+        return True
+
+
+    def OnSaveDocument(self, filename):
+        """
+        Constructs an output file for the given filename (which must
+        not be empty), and calls SaveObject. If SaveObject returns true, the
+        document is set to unmodified; otherwise, an error message box is
+        displayed.
+        """
+        if not filename:
+            return False
+
+        msgTitle = wx.GetApp().GetAppName()
+        if not msgTitle:
+            msgTitle = _("File Error")
+
+        backupFilename = None
+        try:
+            # if current file exists, move it to a safe place temporarily
+            if os.path.exists(filename):
+
+                # Check if read-only.
+                if not os.access(filename, os.W_OK):
+                    wx.MessageBox("Could not save '%s'.  No write permission to overwrite existing file." % FileNameFromPath(filename),
+                                  msgTitle,
+                                  wx.OK | wx.ICON_EXCLAMATION,
+                                  self.GetDocumentWindow())
+                    return False
+
+                i = 1
+                backupFilename = "%s.bak%s" % (filename, i)
+                while os.path.exists(backupFilename):
+                    i += 1
+                    backupFilename = "%s.bak%s" % (filename, i)
+                os.rename(filename, backupFilename)
+
+            fileObject = file(filename, 'w')
+            self.SaveObject(fileObject)
+
+            if backupFilename:
+                os.remove(backupFilename)
+        except:
+            # save failed, restore old file
+            if backupFilename:
+                os.remove(filename)
+                os.rename(backupFilename, filename)
+
+            wx.MessageBox("Could not save '%s'.  %s" % (FileNameFromPath(filename), sys.exc_value),
+                          msgTitle,
+                          wx.OK | wx.ICON_EXCLAMATION,
+                          self.GetDocumentWindow())
+            return False
+
+        self.SetFilename(filename, True)
+        self.Modify(False)
+        self.SetDocumentSaved(True)
+        #if wx.Platform == '__WXMAC__':  # Not yet implemented in wxPython
+        #    wx.FileName(file).MacSetDefaultTypeAndCreator()
+        return True
+
+
+    def OnOpenDocument(self, filename):
+        """
+        Constructs an input file for the given filename (which must not
+        be empty), and calls LoadObject. If LoadObject returns true, the
+        document is set to unmodified; otherwise, an error message box is
+        displayed. The document's views are notified that the filename has
+        changed, to give windows an opportunity to update their titles. All of
+        the document's views are then updated.
+        """
+        if not self.OnSaveModified():
+            return False
+
+        msgTitle = wx.GetApp().GetAppName()
+        if not msgTitle:
+            msgTitle = _("File Error")
+
+        fileObject = file(filename, 'r')
+        try:
+            self.LoadObject(fileObject)
+        except:
+            wx.MessageBox("Could not open '%s'.  %s" % (FileNameFromPath(filename), sys.exc_value),
+                          msgTitle,
+                          wx.OK | wx.ICON_EXCLAMATION,
+                          self.GetDocumentWindow())
+            return False
+
+        self.SetFilename(filename, True)
+        self.Modify(False)
+        self.SetDocumentSaved(True)
+        self.UpdateAllViews()
+        return True
+
+
+    def LoadObject(self, file):
+        """
+        Override this function and call it from your own LoadObject before
+        loading your own data. LoadObject is called by the framework
+        automatically when the document contents need to be loaded.
+
+        Note that the wxPython version simply sends you a Python file object,
+        so you can use pickle.
+        """
+        return True
+
+
+    def SaveObject(self, file):
+        """
+        Override this function and call it from your own SaveObject before
+        saving your own data. SaveObject is called by the framework
+        automatically when the document contents need to be saved.
+
+        Note that the wxPython version simply sends you a Python file object,
+        so you can use pickle.
+        """
+        return True
+
+
+    def Revert(self):
+        """
+        Override this function to revert the document to its last saved state.
+        """
+        return False
+
+
+    def GetPrintableName(self):
+        """
+        Copies a suitable document name into the supplied name buffer.
+        The default function uses the title, or if there is no title, uses the
+        filename; or if no filename, the string 'Untitled'.
+        """
+        if self._documentTitle:
+            return self._documentTitle
+        elif self._documentFile:
+            return FileNameFromPath(self._documentFile)
+        else:
+            return _("Untitled")
+
+
+    def GetDocumentWindow(self):
+        """
+        Intended to return a suitable window for using as a parent for
+        document-related dialog boxes. By default, uses the frame associated
+        with the first view.
+        """
+        if len(self._documentViews) > 0:
+            return self._documentViews[0].GetFrame()
+        else:
+            return wx.GetApp().GetTopWindow()
+
+
+    def OnCreateCommandProcessor(self):
+        """
+        Override this function if you want a different (or no) command
+        processor to be created when the document is created. By default, it
+        returns an instance of wxCommandProcessor.
+        """
+        return CommandProcessor()
+
+
+    def OnSaveModified(self):
+        """
+        If the document has been modified, prompts the user to ask if the
+        changes should be changed. If the user replies Yes, the Save function
+        is called. If No, the document is marked as unmodified and the
+        function succeeds. If Cancel, the function fails.
+        """
+        if not self.IsModified():
+            return True
+
+        msgTitle = wx.GetApp().GetAppName()
+        if not msgTitle:
+            msgTitle = _("Warning")
+
+        res = wx.MessageBox(_("Save changes to '%s'?") % self.GetPrintableName(),
+                            msgTitle,
+                            wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION,
+                            self.GetDocumentWindow())
+
+        if res == wx.NO:
+            self.Modify(False)
+            return True
+        elif res == wx.YES:
+            return self.Save()
+        else: # elif res == wx.CANCEL:
+            return False
+
+
+    def Draw(context):
+        """
+        Called by printing framework to draw the view.
+        """
+        return True
+
+
+    def AddView(self, view):
+        """
+        If the view is not already in the list of views, adds the view and
+        calls OnChangedViewList.
+        """
+        if not view in self._documentViews:
+            self._documentViews.append(view)
+            self.OnChangedViewList()
+        return True
+
+
+    def RemoveView(self, view):
+        """
+        Removes the view from the document's list of views, and calls
+        OnChangedViewList.
+        """
+        if view in self._documentViews:
+            self._documentViews.remove(view)
+            self.OnChangedViewList()
+        return True
+
+
+    def OnCreate(self, path, flags):
+        """
+        The default implementation calls DeleteContents (an empty
+        implementation) sets the modified flag to false. Override this to
+        supply additional behaviour when the document is closed with Close.
+        """
+        return self.GetDocumentTemplate().CreateView(self, flags)
+
+
+    def OnChangedViewList(self):
+        """
+        Called when a view is added to or deleted from this document. The
+        default implementation saves and deletes the document if no views
+        exist (the last one has just been removed).
+        """
+        if len(self._documentViews) == 0:
+            if self.OnSaveModified():
+                pass # C version does a delete but Python will garbage collect
+
+
+    def UpdateAllViews(self, sender = None, hint = None):
+        """
+        Updates all views. If sender is non-NULL, does not update this view.
+        hint represents optional information to allow a view to optimize its
+        update.
+        """
+        for view in self._documentViews:
+            if view != sender:
+                view.OnUpdate(sender, hint)
+
+
+    def NotifyClosing(self):
+        """
+        Notifies the views that the document is going to close.
+        """
+        for view in self._documentViews:
+            view.OnClosingDocument()
+
+
+    def SetFilename(self, filename, notifyViews = False):
+        """
+        Sets the filename for this document. Usually called by the framework.
+        If notifyViews is true, wxView.OnChangeFilename is called for all
+        views.
+        """
+        self._documentFile = filename
+        if notifyViews:
+            for view in self._documentViews:
+                view.OnChangeFilename()
+
+
+class View(wx.EvtHandler):
+    """
+    The view class can be used to model the viewing and editing component of
+    an application's file-based data. It is part of the document/view
+    framework supported by wxWindows, and cooperates with the wxDocument,
+    wxDocTemplate and wxDocManager classes.
+    """
+
+    def __init__(self):
+        """
+        Constructor. Define your own default constructor to initialize
+        application-specific data.
+        """
+        wx.EvtHandler.__init__(self)
+        self._viewDocument = None
+        self._viewFrame = None
+
+
+    def Destroy(self):
+        """
+        Destructor. Removes itself from the document's list of views.
+        """
+        if self._viewDocument:
+            self._viewDocument.RemoveView(self)
+        wx.EvtHandler.Destroy(self)
+
+
+    def ProcessEvent(self, event):
+        """
+        Processes an event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        if not self.GetDocument() or not self.GetDocument().ProcessEvent(event):
+            return False
+        else:
+            return True
+
+
+    def ProcessUpdateUIEvent(self, event):
+        """
+        Processes a UI event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        return False
+
+
+    def OnActivateView(self, activate, activeView, deactiveView):
+        """
+        Called when a view is activated by means of wxView::Activate. The
+        default implementation does nothing.
+        """
+        pass
+
+
+    def OnClosingDocument(self):
+        """
+        Override this to clean up the view when the document is being closed.
+        The default implementation does nothing.
+        """
+        pass
+
+
+    def OnDraw(self, dc):
+        """
+        Override this to draw the view for the printing framework.  The
+        default implementation does nothing.
+        """
+        pass
+
+
+    def OnPrint(self, dc, info):
+        """
+        Override this to print the view for the printing framework.  The
+        default implementation calls View.OnDraw.
+        """
+        self.OnDraw(dc)
+
+
+    def OnUpdate(self, sender, hint):
+        """
+        Called when the view should be updated. sender is a pointer to the
+        view that sent the update request, or NULL if no single view requested
+        the update (for instance, when the document is opened). hint is as yet
+        unused but may in future contain application-specific information for
+        making updating more efficient.
+        """
+        pass
+
+
+    def OnChangeFilename(self):
+        """
+        Called when the filename has changed. The default implementation
+        constructs a suitable title and sets the title of the view frame (if
+        any).
+        """
+        if self.GetFrame():
+            appName = wx.GetApp().GetAppName()
+            if not self.GetDocument():
+                if appName:
+                    title = appName
+                else:
+                    return
+            else:
+                if appName and not isinstance(self.GetFrame(), DocMDIChildFrame):  # Don't need appname in title for MDI
+                    title = appName + _(" - ")
+                else:
+                    title = ''
+                self.GetFrame().SetTitle(title + self.GetDocument().GetPrintableName())
+
+
+    def GetDocument(self):
+        """
+        Returns the document associated with the view.
+        """
+        return self._viewDocument
+
+
+    def SetDocument(self, doc):
+        """
+        Associates the given document with the view. Normally called by the
+        framework.
+        """
+        self._viewDocument = doc
+        if doc:
+            doc.AddView(self)
+
+
+    def GetViewName(self):
+        """
+        Gets the name associated with the view (passed to the wxDocTemplate
+        constructor). Not currently used by the framework.
+        """
+        return self._viewTypeName
+
+
+    def SetViewName(self, name):
+        """
+        Sets the view type name. Should only be called by the framework.
+        """
+        self._viewTypeName = name
+
+
+    def Close(self, deleteWindow = True):
+        """
+        Closes the view by calling OnClose. If deleteWindow is true, this
+        function should delete the window associated with the view.
+        """
+        if self.OnClose(deleteWindow = deleteWindow):
+            return True
+        else:
+            return False
+
+
+    def Activate(self, activate = True):
+        """
+        Call this from your view frame's OnActivate member to tell the
+        framework which view is currently active. If your windowing system
+        doesn't call OnActivate, you may need to call this function from
+        OnMenuCommand or any place where you know the view must be active, and
+        the framework will need to get the current view.
+
+        The prepackaged view frame wxDocChildFrame calls wxView.Activate from
+        its OnActivate member and from its OnMenuCommand member.
+        """
+        if self.GetDocument() and self.GetDocumentManager():
+            self.OnActivateView(activate, self, self.GetDocumentManager().GetCurrentView())
+            self.GetDocumentManager().ActivateView(self, activate)
+
+
+    def OnClose(self, deleteWindow = True):
+        """
+        Implements closing behaviour. The default implementation calls
+        wxDocument.Close to close the associated document. Does not delete the
+        view. The application may wish to do some cleaning up operations in
+        this function, if a call to wxDocument::Close succeeded. For example,
+        if your application's all share the same window, you need to
+        disassociate the window from the view and perhaps clear the window. If
+        deleteWindow is true, delete the frame associated with the view.
+        """
+        if self.GetDocument():
+            return self.GetDocument().Close()
+        else:
+            return True
+
+
+    def OnCreate(self, doc, flags):
+        """
+        wxDocManager or wxDocument creates a wxView via a wxDocTemplate. Just
+        after the wxDocTemplate creates the wxView, it calls wxView::OnCreate.
+        In its OnCreate member function, the wxView can create a
+        wxDocChildFrame or a derived class. This wxDocChildFrame provides user
+        interface elements to view and/or edit the contents of the wxDocument.
+
+        By default, simply returns true. If the function returns false, the
+        view will be deleted.
+        """
+        return True
+
+
+    def OnCreatePrintout(self):
+        """
+        Returns a wxPrintout object for the purposes of printing. It should
+        create a new object every time it is called; the framework will delete
+        objects it creates.
+
+        By default, this function returns an instance of wxDocPrintout, which
+        prints and previews one page by calling wxView.OnDraw.
+
+        Override to return an instance of a class other than wxDocPrintout.
+        """
+        return DocPrintout(self)
+
+
+    def GetFrame(self):
+        """
+        Gets the frame associated with the view (if any). Note that this
+        "frame" is not a wxFrame at all in the generic MDI implementation
+        which uses the notebook pages instead of the frames and this is why
+        this method returns a wxWindow and not a wxFrame.
+        """
+        return self._viewFrame
+
+
+    def SetFrame(self, frame):
+        """
+        Sets the frame associated with this view. The application should call
+        this if possible, to tell the view about the frame.  See GetFrame for
+        the explanation about the mismatch between the "Frame" in the method
+        name and the type of its parameter.
+        """
+        self._viewFrame = frame
+
+
+    def GetDocumentManager(self):
+        """
+        Returns the document manager instance associated with this view.
+        """
+        if self._viewDocument:
+            return self.GetDocument().GetDocumentManager()
+        else:
+            return None
+
+
+class DocTemplate(wx.Object):
+    """
+    The wxDocTemplate class is used to model the relationship between a
+    document class and a view class.
+    """
+
+
+    def __init__(self, manager, description, filter, dir, ext, docTypeName, viewTypeName, docType, viewType, flags = DEFAULT_TEMPLATE_FLAGS, icon = None):
+        """
+        Constructor. Create instances dynamically near the start of your
+        application after creating a wxDocManager instance, and before doing
+        any document or view operations.
+
+        manager is the document manager object which manages this template.
+
+        description is a short description of what the template is for. This
+        string will be displayed in the file filter list of Windows file
+        selectors.
+
+        filter is an appropriate file filter such as *.txt.
+
+        dir is the default directory to use for file selectors.
+
+        ext is the default file extension (such as txt).
+
+        docTypeName is a name that should be unique for a given type of
+        document, used for gathering a list of views relevant to a
+        particular document.
+
+        viewTypeName is a name that should be unique for a given view.
+
+        docClass is a Python class. If this is not supplied, you will need to
+        derive a new wxDocTemplate class and override the CreateDocument
+        member to return a new document instance on demand.
+
+        viewClass is a Python class. If this is not supplied, you will need to
+        derive a new wxDocTemplate class and override the CreateView member to
+        return a new view instance on demand.
+
+        flags is a bit list of the following:
+        wx.TEMPLATE_VISIBLE The template may be displayed to the user in
+        dialogs.
+
+        wx.TEMPLATE_INVISIBLE The template may not be displayed to the user in
+        dialogs.
+
+        wx.DEFAULT_TEMPLATE_FLAGS Defined as wxTEMPLATE_VISIBLE.
+        """
+        self._docManager = manager
+        self._description = description
+        self._fileFilter = filter
+        self._directory = dir
+        self._defaultExt = ext
+        self._docTypeName = docTypeName
+        self._viewTypeName = viewTypeName
+        self._docType = docType
+        self._viewType = viewType
+        self._flags = flags
+        self._icon = icon
+
+        self._docManager.AssociateTemplate(self)
+
+
+    def GetDefaultExtension(self):
+        """
+        Returns the default file extension for the document data, as passed to
+        the document template constructor.
+        """
+        return self._defaultExt
+
+
+    def SetDefaultExtension(self, defaultExt):
+        """
+        Sets the default file extension.
+        """
+        self._defaultExt = defaultExt
+
+
+    def GetDescription(self):
+        """
+        Returns the text description of this template, as passed to the
+        document template constructor.
+        """
+        return self._description
+
+
+    def SetDescription(self, description):
+        """
+        Sets the template description.
+        """
+        self._description = description
+
+
+    def GetDirectory(self):
+        """
+        Returns the default directory, as passed to the document template
+        constructor.
+        """
+        return self._directory
+
+
+    def SetDirectory(self, dir):
+        """
+        Sets the default directory.
+        """
+        self._directory = dir
+
+
+    def GetDocumentManager(self):
+        """
+        Returns the document manager instance for which this template was
+        created.
+        """
+        return self._docManager
+
+
+    def SetDocumentManager(self, manager):
+        """
+        Sets the document manager instance for which this template was
+        created. Should not be called by the application.
+        """
+        self._docManager = manager
+
+
+    def GetFileFilter(self):
+        """
+        Returns the file filter, as passed to the document template
+        constructor.
+        """
+        return self._fileFilter
+
+
+    def SetFileFilter(self, filter):
+        """
+        Sets the file filter.
+        """
+        self._fileFilter = filter
+
+
+    def GetFlags(self):
+        """
+        Returns the flags, as passed to the document template constructor.
+        (see the constructor description for more details).
+        """
+        return self._flags
+
+
+    def SetFlags(self, flags):
+        """
+        Sets the internal document template flags (see the constructor
+        description for more details).
+        """
+        self._flags = flags
+
+
+    def GetIcon(self):
+        """
+        Returns the icon, as passed to the document template
+        constructor.  This method has been added to wxPython and is
+        not in wxWindows.
+        """
+        return self._icon
+
+
+    def SetIcon(self, flags):
+        """
+        Sets the icon.  This method has been added to wxPython and is not
+        in wxWindows.
+        """
+        self._icon = icon
+
+
+    def GetDocumentType(self):
+        """
+        Returns the Python document class, as passed to the document template
+        constructor.
+        """
+        return self._docType
+
+
+    def GetViewType(self):
+        """
+        Returns the Python view class, as passed to the document template
+        constructor.
+        """
+        return self._viewType
+
+
+    def IsVisible(self):
+        """
+        Returns true if the document template can be shown in user dialogs,
+        false otherwise.
+        """
+        return (self._flags & TEMPLATE_VISIBLE) == TEMPLATE_VISIBLE
+
+
+    def GetDocumentName(self):
+        """
+        Returns the document type name, as passed to the document template
+        constructor.
+        """
+        return self._docTypeName
+
+
+    def GetViewName(self):
+        """
+        Returns the view type name, as passed to the document template
+        constructor.
+        """
+        return self._viewTypeName
+
+
+    def CreateDocument(self, path, flags):
+        """
+        Creates a new instance of the associated document class. If you have
+        not supplied a class to the template constructor, you will need to
+        override this function to return an appropriate document instance.
+        """
+        doc = self._docType()
+        doc.SetFilename(path)
+        doc.SetDocumentTemplate(self)
+        self.GetDocumentManager().AddDocument(doc)
+        doc.SetCommandProcessor(doc.OnCreateCommandProcessor())
+        if doc.OnCreate(path, flags):
+            return doc
+        else:
+            if doc in self.GetDocumentManager().GetDocuments():
+                doc.DeleteAllViews()
+            return None
+
+
+    def CreateView(self, doc, flags):
+        """
+        Creates a new instance of the associated document view. If you have
+        not supplied a class to the template constructor, you will need to
+        override this function to return an appropriate view instance.
+        """
+        view = self._viewType()
+        view.SetDocument(doc)
+        if view.OnCreate(doc, flags):
+            return view
+        else:
+            view.Destroy()
+            return None
+
+
+    def FileMatchesTemplate(self, path):
+        """
+        Returns True if the path's extension matches one of this template's
+        file filter extensions.
+        """
+        ext = FindExtension(path)
+        if not ext: return False
+        return ext in self.GetFileFilter()
+        # return self.GetDefaultExtension() == FindExtension(path)
+
+
+class DocManager(wx.EvtHandler):
+    """
+    The wxDocManager class is part of the document/view framework supported by
+    wxWindows, and cooperates with the wxView, wxDocument and wxDocTemplate
+    classes.
+    """
+
+    def __init__(self, flags = DEFAULT_DOCMAN_FLAGS, initialize = True):
+        """
+        Constructor. Create a document manager instance dynamically near the
+        start of your application before doing any document or view operations.
+
+        flags is used in the Python version to indicate whether the document
+        manager is in DOC_SDI or DOC_MDI mode.
+
+        If initialize is true, the Initialize function will be called to
+        create a default history list object. If you derive from wxDocManager,
+        you may wish to call the base constructor with false, and then call
+        Initialize in your own constructor, to allow your own Initialize or
+        OnCreateFileHistory functions to be called.
+        """
+
+        wx.EvtHandler.__init__(self)
+
+        self._defaultDocumentNameCounter = 1
+        self._flags = flags
+        self._currentView = None
+        self._lastActiveView = None
+        self._maxDocsOpen = 10000
+        self._fileHistory = None
+        self._templates = []
+        self._docs = []
+        self._lastDirectory = ""
+
+        if initialize:
+            self.Initialize()
+
+        wx.EVT_MENU(self, wx.ID_OPEN, self.OnFileOpen)
+        wx.EVT_MENU(self, wx.ID_CLOSE, self.OnFileClose)
+        wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.OnFileCloseAll)
+        wx.EVT_MENU(self, wx.ID_REVERT, self.OnFileRevert)
+        wx.EVT_MENU(self, wx.ID_NEW, self.OnFileNew)
+        wx.EVT_MENU(self, wx.ID_SAVE, self.OnFileSave)
+        wx.EVT_MENU(self, wx.ID_SAVEAS, self.OnFileSaveAs)
+        wx.EVT_MENU(self, wx.ID_UNDO, self.OnUndo)
+        wx.EVT_MENU(self, wx.ID_REDO, self.OnRedo)
+        wx.EVT_MENU(self, wx.ID_PRINT, self.OnPrint)
+        wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.OnPrintSetup)
+        wx.EVT_MENU(self, wx.ID_PREVIEW, self.OnPreview)
+
+        wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.OnUpdateFileOpen)
+        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.OnUpdateFileClose)
+        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.OnUpdateFileCloseAll)
+        wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.OnUpdateFileRevert)
+        wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.OnUpdateFileNew)
+        wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.OnUpdateFileSave)
+        wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.OnUpdateFileSaveAs)
+        wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.OnUpdateUndo)
+        wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.OnUpdateRedo)
+        wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.OnUpdatePrint)
+        wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.OnUpdatePrintSetup)
+        wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.OnUpdatePreview)
+
+
+    def Destroy(self):
+        """
+        Destructor.
+        """
+        self.Clear()
+        wx.EvtHandler.Destroy(self)
+
+
+    def GetFlags(self):
+        """
+        Returns the document manager's flags.  This method has been
+        added to wxPython and is not in wxWindows.
+        """
+        return self._flags
+
+
+    def CloseDocument(self, doc, force = True):
+        """
+        Closes the specified document.
+        """
+        if doc.Close() or force:
+            doc.DeleteAllViews()
+            if doc in self._docs:
+                doc.Destroy()
+            return True
+        return False
+
+
+    def CloseDocuments(self, force = True):
+        """
+        Closes all currently opened documents.
+        """
+        for document in self._docs[::-1]:  # Close in lifo (reverse) order.  We clone the list to make sure we go through all docs even as they are deleted
+            if not self.CloseDocument(document, force):
+                return False
+            document.DeleteAllViews() # Implicitly delete the document when the last view is removed
+        return True
+
+
+    def Clear(self, force = True):
+        """
+        Closes all currently opened document by callling CloseDocuments and
+        clears the document manager's templates.
+        """
+        if not self.CloseDocuments(force):
+            return False
+        self._templates = []
+        return True
+
+
+    def Initialize(self):
+        """
+        Initializes data; currently just calls OnCreateFileHistory. Some data
+        cannot always be initialized in the constructor because the programmer
+        must be given the opportunity to override functionality. In fact
+        Initialize is called from the wxDocManager constructor, but this can
+        be vetoed by passing false to the second argument, allowing the
+        derived class's constructor to call Initialize, possibly calling a
+        different OnCreateFileHistory from the default.
+
+        The bottom line: if you're not deriving from Initialize, forget it and
+        construct wxDocManager with no arguments.
+        """
+        self.OnCreateFileHistory()
+        return True
+
+
+    def OnCreateFileHistory(self):
+        """
+        A hook to allow a derived class to create a different type of file
+        history. Called from Initialize.
+        """
+        self._fileHistory = wx.FileHistory()
+
+
+    def OnFileClose(self, event):
+        """
+        Closes and deletes the currently active document.
+        """
+        doc = self.GetCurrentDocument()
+        if doc:
+            doc.DeleteAllViews()
+            if doc in self._docs:
+                self._docs.remove(doc)
+
+
+    def OnFileCloseAll(self, event):
+        """
+        Closes and deletes all the currently opened documents.
+        """
+        return self.CloseDocuments(force = False)
+
+
+    def OnFileNew(self, event):
+        """
+        Creates a new document and reads in the selected file.
+        """
+        self.CreateDocument('', DOC_NEW)
+
+
+    def OnFileOpen(self, event):
+        """
+        Creates a new document and reads in the selected file.
+        """
+        if not self.CreateDocument('', 0):
+            self.OnOpenFileFailure()
+
+
+    def OnFileRevert(self, event):
+        """
+        Reverts the current document by calling wxDocument.Save for the current
+        document.
+        """
+        doc = self.GetCurrentDocument()
+        if not doc:
+            return
+        doc.Revert()
+
+
+    def OnFileSave(self, event):
+        """
+        Saves the current document by calling wxDocument.Save for the current
+        document.
+        """
+        doc = self.GetCurrentDocument()
+        if not doc:
+            return
+        doc.Save()
+
+
+    def OnFileSaveAs(self, event):
+        """
+        Calls wxDocument.SaveAs for the current document.
+        """
+        doc = self.GetCurrentDocument()
+        if not doc:
+            return
+        doc.SaveAs()
+
+
+    def OnPrint(self, event):
+        """
+        Prints the current document by calling its View's OnCreatePrintout
+        method.
+        """
+        view = self.GetCurrentView()
+        if not view:
+            return
+
+        printout = view.OnCreatePrintout()
+        if printout:
+            pdd = wx.PrintDialogData()
+            printer = wx.Printer(pdd)
+            printer.Print(view.GetFrame(), printout) # , True)
+
+
+    def OnPrintSetup(self, event):
+        """
+        Presents the print setup dialog.
+        """
+        view = self.GetCurrentView()
+        if view:
+            parentWin = view.GetFrame()
+        else:
+            parentWin = wx.GetApp().GetTopWindow()
+
+        data = wx.PrintDialogData()
+        printDialog = wx.PrintDialog(parentWin, data)
+        printDialog.GetPrintDialogData().SetSetupDialog(True)
+        printDialog.ShowModal()
+        # TODO: Confirm that we don't have to remember PrintDialogData
+
+
+    def OnPreview(self, event):
+        """
+        Previews the current document by calling its View's OnCreatePrintout
+        method.
+        """
+        view = self.GetCurrentView()
+        if not view:
+            return
+
+        printout = view.OnCreatePrintout()
+        if printout:
+            # Pass two printout objects: for preview, and possible printing.
+            preview = wx.PrintPreview(printout, view.OnCreatePrintout())
+            # wxWindows source doesn't use base frame's pos, size, and icon, but did it this way so it would work like MS Office etc.
+            mimicFrame =  wx.GetApp().GetTopWindow()
+            frame = wx.PreviewFrame(preview, mimicFrame, _("Print Preview"), mimicFrame.GetPosition(), mimicFrame.GetSize())
+            frame.SetIcon(mimicFrame.GetIcon())
+            frame.SetTitle(mimicFrame.GetTitle() + _(" - Preview"))
+            frame.Initialize()
+            frame.Show(True)
+
+
+    def OnUndo(self, event):
+        """
+        Issues an Undo command to the current document's command processor.
+        """
+        doc = self.GetCurrentDocument()
+        if not doc:
+            return
+        if doc.GetCommandProcessor():
+            doc.GetCommandProcessor().Undo()
+
+
+    def OnRedo(self, event):
+        """
+        Issues a Redo command to the current document's command processor.
+        """
+        doc = self.GetCurrentDocument()
+        if not doc:
+            return
+        if doc.GetCommandProcessor():
+            doc.GetCommandProcessor().Redo()
+
+
+    def OnUpdateFileOpen(self, event):
+        """
+        Updates the user interface for the File Open command.
+        """
+        event.Enable(True)
+
+
+    def OnUpdateFileClose(self, event):
+        """
+        Updates the user interface for the File Close command.
+        """
+        event.Enable(self.GetCurrentDocument() != None)
+
+
+    def OnUpdateFileCloseAll(self, event):
+        """
+        Updates the user interface for the File Close All command.
+        """
+        event.Enable(self.GetCurrentDocument() != None)
+
+
+    def OnUpdateFileRevert(self, event):
+        """
+        Updates the user interface for the File Revert command.
+        """
+        event.Enable(self.GetCurrentDocument() != None)
+
+
+    def OnUpdateFileNew(self, event):
+        """
+        Updates the user interface for the File New command.
+        """
+        return True
+
+
+    def OnUpdateFileSave(self, event):
+        """
+        Updates the user interface for the File Save command.
+        """
+        doc = self.GetCurrentDocument()
+        event.Enable(doc != None and doc.IsModified())
+
+
+    def OnUpdateFileSaveAs(self, event):
+        """
+        Updates the user interface for the File Save As command.
+        """
+        event.Enable(self.GetCurrentDocument() != None)
+
+
+    def OnUpdateUndo(self, event):
+        """
+        Updates the user interface for the Undo command.
+        """
+        doc = self.GetCurrentDocument()
+        event.Enable(doc != None and doc.GetCommandProcessor() != None and doc.GetCommandProcessor().CanUndo())
+        if doc and doc.GetCommandProcessor():
+            doc.GetCommandProcessor().SetMenuStrings()
+        else:
+            event.SetText(_("Undo") + '\t' + _('Ctrl+Z'))
+
+
+    def OnUpdateRedo(self, event):
+        """
+        Updates the user interface for the Redo command.
+        """
+        doc = self.GetCurrentDocument()
+        event.Enable(doc != None and doc.GetCommandProcessor() != None and doc.GetCommandProcessor().CanRedo())
+        if doc and doc.GetCommandProcessor():
+            doc.GetCommandProcessor().SetMenuStrings()
+        else:
+            event.SetText(_("Redo") + '\t' + _('Ctrl+Y'))
+
+
+    def OnUpdatePrint(self, event):
+        """
+        Updates the user interface for the Print command.
+        """
+        event.Enable(self.GetCurrentDocument() != None)
+
+
+    def OnUpdatePrintSetup(self, event):
+        """
+        Updates the user interface for the Print Setup command.
+        """
+        return True
+
+
+    def OnUpdatePreview(self, event):
+        """
+        Updates the user interface for the Print Preview command.
+        """
+        event.Enable(self.GetCurrentDocument() != None)
+
+
+    def GetCurrentView(self):
+        """
+        Returns the currently active view.
+        """
+        if self._currentView:
+            return self._currentView
+        if len(self._docs) == 1:
+            return self._docs[0].GetFirstView()
+        return None
+
+
+    def GetLastActiveView(self):
+        """
+        Returns the last active view.  This is used in the SDI framework where dialogs can be mistaken for a view
+        and causes the framework to deactivete the current view.  This happens when something like a custom dialog box used
+        to operate on the current view is shown.
+        """
+        if len(self._docs) >= 1:
+            return self._lastActiveView
+        else:
+            return None
+
+
+    def ProcessEvent(self, event):
+        """
+        Processes an event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        view = self.GetCurrentView()
+        if view:
+            if view.ProcessEvent(event):
+                return True
+        id = event.GetId()
+        if id == wx.ID_OPEN:
+            self.OnFileOpen(event)
+            return True
+        elif id == wx.ID_CLOSE:
+            self.OnFileClose(event)
+            return True
+        elif id == wx.ID_CLOSE_ALL:
+            self.OnFileCloseAll(event)
+            return True
+        elif id == wx.ID_REVERT:
+            self.OnFileRevert(event)
+            return True
+        elif id == wx.ID_NEW:
+            self.OnFileNew(event)
+            return True
+        elif id == wx.ID_SAVE:
+            self.OnFileSave(event)
+            return True
+        elif id == wx.ID_SAVEAS:
+            self.OnFileSaveAs(event)
+            return True
+        elif id == wx.ID_UNDO:
+            self.OnUndo(event)
+            return True
+        elif id == wx.ID_REDO:
+            self.OnRedo(event)
+            return True
+        elif id == wx.ID_PRINT:
+            self.OnPrint(event)
+            return True
+        elif id == wx.ID_PRINT_SETUP:
+            self.OnPrintSetup(event)
+            return True
+        elif id == wx.ID_PREVIEW:
+            self.OnPreview(event)
+            return True
+        else:
+            return False
+
+
+    def ProcessUpdateUIEvent(self, event):
+        """
+        Processes a UI event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        id = event.GetId()
+        view = self.GetCurrentView()
+        if view:
+            if view.ProcessUpdateUIEvent(event):
+                return True
+        if id == wx.ID_OPEN:
+            self.OnUpdateFileOpen(event)
+            return True
+        elif id == wx.ID_CLOSE:
+            self.OnUpdateFileClose(event)
+            return True
+        elif id == wx.ID_CLOSE_ALL:
+            self.OnUpdateFileCloseAll(event)
+            return True
+        elif id == wx.ID_REVERT:
+            self.OnUpdateFileRevert(event)
+            return True
+        elif id == wx.ID_NEW:
+            self.OnUpdateFileNew(event)
+            return True
+        elif id == wx.ID_SAVE:
+            self.OnUpdateFileSave(event)
+            return True
+        elif id == wx.ID_SAVEAS:
+            self.OnUpdateFileSaveAs(event)
+            return True
+        elif id == wx.ID_UNDO:
+            self.OnUpdateUndo(event)
+            return True
+        elif id == wx.ID_REDO:
+            self.OnUpdateRedo(event)
+            return True
+        elif id == wx.ID_PRINT:
+            self.OnUpdatePrint(event)
+            return True
+        elif id == wx.ID_PRINT_SETUP:
+            self.OnUpdatePrintSetup(event)
+            return True
+        elif id == wx.ID_PREVIEW:
+            self.OnUpdatePreview(event)
+            return True
+        else:
+            return False
+
+
+    def CreateDocument(self, path, flags = 0):
+        """
+        Creates a new document in a manner determined by the flags parameter,
+        which can be:
+
+        wx.lib.docview.DOC_NEW Creates a fresh document.
+        wx.lib.docview.DOC_SILENT Silently loads the given document file.
+
+        If wx.lib.docview.DOC_NEW is present, a new document will be created and returned,
+        possibly after asking the user for a template to use if there is more
+        than one document template. If wx.lib.docview.DOC_SILENT is present, a new document
+        will be created and the given file loaded into it. If neither of these
+        flags is present, the user will be presented with a file selector for
+        the file to load, and the template to use will be determined by the
+        extension (Windows) or by popping up a template choice list (other
+        platforms).
+
+        If the maximum number of documents has been reached, this function
+        will delete the oldest currently loaded document before creating a new
+        one.
+
+        wxPython version supports the document manager's wx.lib.docview.DOC_OPEN_ONCE flag.
+        """
+        templates = []
+        for temp in self._templates:
+            if temp.IsVisible():
+                templates.append(temp)
+        if len(templates) == 0:
+            return None
+
+        if len(self.GetDocuments()) >= self._maxDocsOpen:
+           doc = self.GetDocuments()[0]
+           if not self.CloseDocument(doc, False):
+               return None
+
+        if flags & DOC_NEW:
+            if len(templates) == 1:
+                temp = templates[0]
+                newDoc = temp.CreateDocument(path, flags)
+                if newDoc:
+                    newDoc.SetDocumentName(temp.GetDocumentName())
+                    newDoc.SetDocumentTemplate(temp)
+                    newDoc.OnNewDocument()
+                return newDoc
+
+            temp = self.SelectDocumentType(templates)
+            if temp:
+                newDoc = temp.CreateDocument(path, flags)
+                if newDoc:
+                    newDoc.SetDocumentName(temp.GetDocumentName())
+                    newDoc.SetDocumentTemplate(temp)
+                    newDoc.OnNewDocument()
+                return newDoc
+            else:
+                return None
+
+        # Existing document
+        if self.GetFlags() & DOC_OPEN_ONCE:
+            for document in self._docs:
+                if document.GetFilename() == path:
+                    firstView = document.GetFirstView()
+                    if firstView and firstView.GetFrame():
+                        firstView.GetFrame().SetFocus()  # Not in wxWindows code but useful nonetheless
+                        if hasattr(firstView.GetFrame(), "IsIconized") and firstView.GetFrame().IsIconized():  # Not in wxWindows code but useful nonetheless
+                            firstView.GetFrame().Iconize(False)
+                    return None
+
+        if flags & DOC_SILENT:
+            temp = self.FindTemplateForPath(path)
+        else:
+            temp, path = self.SelectDocumentPath(templates, path, flags)
+
+        if temp:
+            newDoc = temp.CreateDocument(path, flags)
+            if newDoc:
+                newDoc.SetDocumentName(temp.GetDocumentName())
+                newDoc.SetDocumentTemplate(temp)
+                if not newDoc.OnOpenDocument(path):
+                    newDoc.DeleteAllViews()  # Implicitly deleted by DeleteAllViews
+                    newDoc.GetFirstView().GetFrame().Destroy() # DeleteAllViews doesn't get rid of the frame, so we'll explicitly destroy it.
+                    return None
+                self.AddFileToHistory(path)
+            return newDoc
+
+        return None
+
+
+    def CreateView(self, document, flags = 0):
+        """
+        Creates a new view for the given document. If more than one view is
+        allowed for the document (by virtue of multiple templates mentioning
+        the same document type), a choice of view is presented to the user.
+        """
+        templates = []
+        for temp in self._templates:
+            if temp.IsVisible():
+                if temp.GetDocumentName() == doc.GetDocumentName():
+                    templates.append(temp)
+        if len(templates) == 0:
+            return None
+
+        if len(templates) == 1:
+            temp = templates[0]
+            view = temp.CreateView(doc, flags)
+            if view:
+                view.SetViewName(temp.GetViewName())
+            return view
+
+        temp = SelectViewType(templates)
+        if temp:
+            view = temp.CreateView(doc, flags)
+            if view:
+                view.SetViewName(temp.GetViewName())
+            return view
+        else:
+            return None
+
+
+    def DeleteTemplate(self, template, flags):
+        """
+        Placeholder, not yet implemented in wxWindows.
+        """
+        pass
+
+
+    def FlushDoc(self, doc):
+        """
+        Placeholder, not yet implemented in wxWindows.
+        """
+        return False
+
+
+    def MatchTemplate(self, path):
+        """
+        Placeholder, not yet implemented in wxWindows.
+        """
+        return None
+
+
+    def GetCurrentDocument(self):
+        """
+        Returns the document associated with the currently active view (if any).
+        """
+        view = self.GetCurrentView()
+        if view:
+            return view.GetDocument()
+        else:
+            return None
+
+
+    def MakeDefaultName(self):
+        """
+        Returns a suitable default name. This is implemented by appending an
+        integer counter to the string "Untitled" and incrementing the counter.
+        """
+        name = _("Untitled %d") % self._defaultDocumentNameCounter
+        self._defaultDocumentNameCounter = self._defaultDocumentNameCounter + 1
+        return name
+
+
+    def MakeFrameTitle(self):
+        """
+        Returns a suitable title for a document frame. This is implemented by
+        appending the document name to the application name.
+        """
+        appName = wx.GetApp().GetAppName()
+        if not doc:
+            title = appName
+        else:
+            docName = doc.GetPrintableName()
+            title = docName + _(" - ") + appName
+        return title
+
+
+    def AddFileToHistory(self, fileName):
+        """
+        Adds a file to the file history list, if we have a pointer to an
+        appropriate file menu.
+        """
+        if self._fileHistory:
+            self._fileHistory.AddFileToHistory(fileName)
+
+
+    def RemoveFileFromHistory(self, i):
+        """
+        Removes a file from the file history list, if we have a pointer to an
+        appropriate file menu.
+        """
+        if self._fileHistory:
+            self._fileHistory.RemoveFileFromHistory(i)
+
+
+    def GetFileHistory(self):
+        """
+        Returns the file history.
+        """
+        return self._fileHistory
+
+
+    def GetHistoryFile(self, i):
+        """
+        Returns the file at index i from the file history.
+        """
+        if self._fileHistory:
+            return self._fileHistory.GetHistoryFile(i)
+        else:
+            return None
+
+
+    def FileHistoryUseMenu(self, menu):
+        """
+        Use this menu for appending recently-visited document filenames, for
+        convenient access. Calling this function with a valid menu enables the
+        history list functionality.
+
+        Note that you can add multiple menus using this function, to be
+        managed by the file history object.
+        """
+        if self._fileHistory:
+            self._fileHistory.UseMenu(menu)
+
+
+    def FileHistoryRemoveMenu(self, menu):
+        """
+        Removes the given menu from the list of menus managed by the file
+        history object.
+        """
+        if self._fileHistory:
+            self._fileHistory.RemoveMenu(menu)
+
+
+    def FileHistoryLoad(self, config):
+        """
+        Loads the file history from a config object.
+        """
+        if self._fileHistory:
+            self._fileHistory.Load(config)
+
+
+    def FileHistorySave(self, config):
+        """
+        Saves the file history into a config object. This must be called
+        explicitly by the application.
+        """
+        if self._fileHistory:
+            self._fileHistory.Save(config)
+
+
+    def FileHistoryAddFilesToMenu(self, menu = None):
+        """
+        Appends the files in the history list, to all menus managed by the
+        file history object.
+
+        If menu is specified, appends the files in the history list to the
+        given menu only.
+        """
+        if self._fileHistory:
+            if menu:
+                self._fileHistory.AddFilesToThisMenu(menu)
+            else:
+                self._fileHistory.AddFilesToMenu()
+
+
+    def GetHistoryFilesCount(self):
+        """
+        Returns the number of files currently stored in the file history.
+        """
+        if self._fileHistory:
+            return self._fileHistory.GetNoHistoryFiles()
+        else:
+            return 0
+
+
+    def FindTemplateForPath(self, path):
+        """
+        Given a path, try to find template that matches the extension. This is
+        only an approximate method of finding a template for creating a
+        document.
+        """
+        for temp in self._templates:
+            if temp.FileMatchesTemplate(path):
+                return temp
+        return None
+
+
+    def FindSuitableParent(self):
+        """
+        Returns a parent frame or dialog, either the frame with the current
+        focus or if there is no current focus the application's top frame.
+        """
+        parent = wx.GetApp().GetTopWindow()
+        focusWindow = wx.Window_FindFocus()
+        if focusWindow:
+            while focusWindow and not isinstance(focusWindow, wx.Dialog) and not isinstance(focusWindow, wx.Frame):
+                focusWindow = focusWindow.GetParent()
+            if focusWindow:
+                parent = focusWindow
+        return parent
+
+
+    def SelectDocumentPath(self, templates, flags, save):
+        """
+        Under Windows, pops up a file selector with a list of filters
+        corresponding to document templates. The wxDocTemplate corresponding
+        to the selected file's extension is returned.
+
+        On other platforms, if there is more than one document template a
+        choice list is popped up, followed by a file selector.
+
+        This function is used in wxDocManager.CreateDocument.
+        """
+        if wx.Platform == "__WXMSW__" or wx.Platform == "__WXGTK__" or wx.Platform == "__WXMAC__":
+            allfilter = ''
+            descr = ''
+            for temp in templates:
+                if temp.IsVisible():
+                    if len(descr) > 0:
+                        descr = descr + _('|')
+                        allfilter = allfilter + _(';')
+                    descr = descr + temp.GetDescription() + _(" (") + temp.GetFileFilter() + _(") |") + temp.GetFileFilter()  # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
+                    allfilter = allfilter + temp.GetFileFilter()
+            descr = _("All") + _(" (") + allfilter + _(") |") + allfilter + _('|') + descr  # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
+        else:
+            descr = _("*.*")
+
+        path = wx.FileSelector(_("Select a File"),
+                               self._lastDirectory,
+                               _(""),
+                               wildcard = descr,
+                               flags = wx.HIDE_READONLY,
+                               parent = self.FindSuitableParent())
+        if path:
+            if not FileExists(path):
+                msgTitle = wx.GetApp().GetAppName()
+                if not msgTitle:
+                    msgTitle = _("File Error")
+                    wx.MessageBox("Could not open '%s'." % FileNameFromPath(path),
+                          msgTitle,
+                          wx.OK | wx.ICON_EXCLAMATION,
+                          parent)
+                    return (None, None)
+            self._lastDirectory = PathOnly(path)
+
+            theTemplate = self.FindTemplateForPath(path)
+            return (theTemplate, path)
+
+        return (None, None)
+
+
+    def OnOpenFileFailure(self):
+        """
+        Called when there is an error opening a file.
+        """
+        pass
+
+
+    def SelectDocumentType(self, temps, sort = False):
+        """
+        Returns a document template by asking the user (if there is more than
+        one template). This function is used in wxDocManager.CreateDocument.
+
+        Parameters
+
+        templates - list of templates from which to choose a desired template.
+
+        sort - If more than one template is passed in in templates, then this
+        parameter indicates whether the list of templates that the user will
+        have to choose from is sorted or not when shown the choice box dialog.
+        Default is false.
+        """
+        templates = []
+        for temp in temps:
+            if temp.IsVisible():
+                want = True
+                for temp2 in templates:
+                    if temp.GetDocumentName() == temp2.GetDocumentName() and temp.GetViewName() == temp2.GetViewName():
+                        want = False
+                        break
+                if want:
+                    templates.append(temp)
+
+        if len(templates) == 0:
+            return None
+        elif len(templates) == 1:
+            return template[0]
+
+        if sort:
+            def tempcmp(a, b):
+                return cmp(a.GetDescription(), b.GetDescription())
+            templates.sort(tempcmp)
+
+        strings = []
+        for temp in templates:
+            strings.append(temp.GetDescription())
+
+        res = wx.GetSingleChoiceIndex(_("Select a document type:"),
+                                      _("Documents"),
+                                      strings,
+                                      self.FindSuitableParent())
+        if res == -1:
+            return None
+        return templates[res]
+
+
+    def SelectViewType(self, temps, sort = False):
+        """
+        Returns a document template by asking the user (if there is more than one template), displaying a list of valid views. This function is used in wxDocManager::CreateView. The dialog normally will not appear because the array of templates only contains those relevant to the document in question, and often there will only be one such.
+        """
+        templates = []
+        strings = []
+        for temp in temps:
+            if temp.IsVisible() and temp.GetViewTypeName():
+                if temp.GetViewName() not in strings:
+                    templates.append(temp)
+                    strings.append(temp.GetViewTypeName())
+
+        if len(templates) == 0:
+            return None
+        elif len(templates) == 1:
+            return templates[0]
+
+        if sort:
+            def tempcmp(a, b):
+                return cmp(a.GetViewTypeName(), b.GetViewTypeName())
+            templates.sort(tempcmp)
+
+        res = wx.GetSingleChoiceIndex(_("Select a document view:"),
+                                      _("Views"),
+                                      strings,
+                                      self.FindSuitableParent())
+        if res == -1:
+            return None
+        return templates[res]
+
+
+    def GetTemplates(self):
+        """
+        Returns the document manager's template list.  This method has been added to
+        wxPython and is not in wxWindows.
+        """
+        return self._templates
+
+
+    def AssociateTemplate(self, docTemplate):
+        """
+        Adds the template to the document manager's template list.
+        """
+        if docTemplate not in self._templates:
+            self._templates.append(docTemplate)
+
+
+    def DisassociateTemplate(self, docTemplate):
+        """
+        Removes the template from the list of templates.
+        """
+        self._templates.remove(docTemplate)
+
+
+    def AddDocument(self, document):
+        """
+        Adds the document to the list of documents.
+        """
+        if document not in self._docs:
+            self._docs.append(document)
+
+
+    def RemoveDocument(self, doc):
+        """
+        Removes the document from the list of documents.
+        """
+        if doc in self._docs:
+            self._docs.remove(doc)
+
+
+    def ActivateView(self, view, activate = True, deleting = False):
+        """
+        Sets the current view.
+        """
+        if activate:
+            self._currentView = view
+            self._lastActiveView = view
+        else:
+            self._currentView = None
+
+
+    def GetMaxDocsOpen(self):
+        """
+        Returns the number of documents that can be open simultaneously.
+        """
+        return self._maxDocsOpen
+
+
+    def SetMaxDocsOpen(self, maxDocsOpen):
+        """
+        Sets the maximum number of documents that can be open at a time. By
+        default, this is 10,000. If you set it to 1, existing documents will
+        be saved and deleted when the user tries to open or create a new one
+        (similar to the behaviour of Windows Write, for example). Allowing
+        multiple documents gives behaviour more akin to MS Word and other
+        Multiple Document Interface applications.
+        """
+        self._maxDocsOpen = maxDocsOpen
+
+
+    def GetDocuments(self):
+        """
+        Returns the list of documents.
+        """
+        return self._docs
+
+
+class DocParentFrame(wx.Frame):
+    """
+    The wxDocParentFrame class provides a default top-level frame for
+    applications using the document/view framework. This class can only be
+    used for SDI (not MDI) parent frames.
+
+    It cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplates
+    classes.
+    """
+
+    def __init__(self, manager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
+        """
+        Constructor.  Note that the event table must be rebuilt for the
+        frame since the EvtHandler is not virtual.
+        """
+        wx.Frame.__init__(self, frame, id, title, pos, size, style)
+        self._docManager = manager
+
+        wx.EVT_CLOSE(self, self.OnCloseWindow)
+
+        wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit)
+        wx.EVT_MENU_RANGE(self, wx.ID_FILE1, wx.ID_FILE9, self.OnMRUFile)
+
+        wx.EVT_MENU(self, wx.ID_NEW, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_OPEN, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_CLOSE, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_REVERT, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_SAVE, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_SAVEAS, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_UNDO, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_REDO, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_PRINT, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_PREVIEW, self.ProcessEvent)
+
+        wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.ProcessUpdateUIEvent)
+
+
+    def ProcessEvent(self, event):
+        """
+        Processes an event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        return self._docManager and self._docManager.ProcessEvent(event)
+
+
+    def ProcessUpdateUIEvent(self, event):
+        """
+        Processes a UI event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        return self._docManager and self._docManager.ProcessUpdateUIEvent(event)
+
+
+    def OnExit(self, event):
+        """
+        Called when File/Exit is chosen and closes the window.
+        """
+        self.Close()
+
+
+    def OnMRUFile(self, event):
+        """
+        Opens the appropriate file when it is selected from the file history
+        menu.
+        """
+        n = event.GetId() - wx.ID_FILE1
+        filename = self._docManager.GetHistoryFile(n)
+        if filename:
+            self._docManager.CreateDocument(filename, DOC_SILENT)
+        else:
+            self._docManager.RemoveFileFromHistory(n)
+            msgTitle = wx.GetApp().GetAppName()
+            if not msgTitle:
+                msgTitle = _("File Error")
+            wx.MessageBox("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list" % FileNameFromPath(file),
+                          msgTitle,
+                          wx.OK | wx.ICON_EXCLAMATION,
+                          self)
+
+
+    def OnCloseWindow(self, event):
+        """
+        Deletes all views and documents. If no user input cancelled the
+        operation, the frame will be destroyed and the application will exit.
+        """
+        if self._docManager.Clear(not event.CanVeto()):
+            self.Destroy()
+        else:
+            event.Veto()
+
+
+class DocChildFrame(wx.Frame):
+    """
+    The wxDocChildFrame class provides a default frame for displaying
+    documents on separate windows. This class can only be used for SDI (not
+    MDI) child frames.
+
+    The class is part of the document/view framework supported by wxWindows,
+    and cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate
+    classes.
+    """
+
+
+    def __init__(self, doc, view, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
+        """
+        Constructor.  Note that the event table must be rebuilt for the
+        frame since the EvtHandler is not virtual.
+        """
+        wx.Frame.__init__(self, frame, id, title, pos, size, style, name)
+        wx.EVT_ACTIVATE(self, self.OnActivate)
+        wx.EVT_CLOSE(self, self.OnCloseWindow)
+        self._childDocument = doc
+        self._childView = view
+        if view:
+            view.SetFrame(self)
+
+        wx.EVT_MENU(self, wx.ID_NEW, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_OPEN, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_CLOSE, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_REVERT, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_SAVE, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_SAVEAS, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_UNDO, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_REDO, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_PRINT, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_PREVIEW, self.ProcessEvent)
+
+        wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.ProcessUpdateUIEvent)
+
+
+    def ProcessEvent(self, event):
+        """
+        Processes an event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        if self._childView:
+            self._childView.Activate(True)
+        if not self._childView or not self._childView.ProcessEvent(event):
+            # IsInstance not working, but who cares just send all the commands up since this isn't a real ProcessEvent like wxWindows
+            # if not isinstance(event, wx.CommandEvent) or not self.GetParent() or not self.GetParent().ProcessEvent(event):
+            if not self.GetParent() or not self.GetParent().ProcessEvent(event):
+                return False
+            else:
+                return True
+        else:
+            return True
+
+
+    def ProcessUpdateUIEvent(self, event):
+        """
+        Processes a UI event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        if self.GetParent():
+            self.GetParent().ProcessUpdateUIEvent(event)
+        else:
+            return False
+
+
+    def OnActivate(self, event):
+        """
+        Activates the current view.
+        """
+        # wx.Frame.OnActivate(event)  This is in the wxWindows docview demo but there is no such method in wxPython, so do a Raise() instead
+        if self._childView:
+            self._childView.Activate(event.GetActive())
+
+
+    def OnCloseWindow(self, event):
+        """
+        Closes and deletes the current view and document.
+        """
+        if self._childView:
+            ans = False
+            if not event.CanVeto():
+                ans = True
+            else:
+                ans = self._childView.Close(deleteWindow = False)
+
+            if ans:
+                self._childView.Activate(False)
+                self._childView.Destroy()
+                self._childView = None
+                if self._childDocument:
+                    self._childDocument.Destroy()  # This isn't in the wxWindows codebase but the document needs to be disposed of somehow
+                    self._childDocument = None
+                self.Destroy()
+            else:
+                event.Veto()
+        else:
+            event.Veto()
+
+
+    def GetDocument(self):
+        """
+        Returns the document associated with this frame.
+        """
+        return self._childDocument
+
+
+    def SetDocument(self, document):
+        """
+        Sets the document for this frame.
+        """
+        self._childDocument = document
+
+
+    def GetView(self):
+        """
+        Returns the view associated with this frame.
+        """
+        return self._childView
+
+
+    def SetView(self, view):
+        """
+        Sets the view for this frame.
+        """
+        self._childView = view
+
+
+class DocMDIParentFrame(wx.MDIParentFrame):
+    """
+    The wxDocMDIParentFrame class provides a default top-level frame for
+    applications using the document/view framework. This class can only be
+    used for MDI parent frames.
+
+    It cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate
+    classes.
+    """
+
+
+    def __init__(self, manager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
+        """
+        Constructor.  Note that the event table must be rebuilt for the
+        frame since the EvtHandler is not virtual.
+        """
+        wx.MDIParentFrame.__init__(self, frame, id, title, pos, size, style, name)
+        self._docManager = manager
+
+        wx.EVT_CLOSE(self, self.OnCloseWindow)
+
+        wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit)
+        wx.EVT_MENU_RANGE(self, wx.ID_FILE1, wx.ID_FILE9, self.OnMRUFile)
+
+        wx.EVT_MENU(self, wx.ID_NEW, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_OPEN, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_CLOSE, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_REVERT, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_SAVE, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_SAVEAS, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_UNDO, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_REDO, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_PRINT, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.ProcessEvent)
+        wx.EVT_MENU(self, wx.ID_PREVIEW, self.ProcessEvent)
+
+        wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.ProcessUpdateUIEvent)
+        wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.ProcessUpdateUIEvent)
+
+
+    def ProcessEvent(self, event):
+        """
+        Processes an event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        return self._docManager and self._docManager.ProcessEvent(event)
+
+
+    def ProcessUpdateUIEvent(self, event):
+        """
+        Processes a UI event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        return self._docManager and self._docManager.ProcessUpdateUIEvent(event)
+
+
+    def OnExit(self, event):
+        """
+        Called when File/Exit is chosen and closes the window.
+        """
+        self.Close()
+
+
+    def OnMRUFile(self, event):
+        """
+        Opens the appropriate file when it is selected from the file history
+        menu.
+        """
+        n = event.GetId() - wx.ID_FILE1
+        filename = self._docManager.GetHistoryFile(n)
+        if filename:
+            self._docManager.CreateDocument(filename, DOC_SILENT)
+        else:
+            self._docManager.RemoveFileFromHistory(n)
+            msgTitle = wx.GetApp().GetAppName()
+            if not msgTitle:
+                msgTitle = _("File Error")
+            wx.MessageBox("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list" % FileNameFromPath(file),
+                          msgTitle,
+                          wx.OK | wx.ICON_EXCLAMATION,
+                          self)
+
+
+    def OnCloseWindow(self, event):
+        """
+        Deletes all views and documents. If no user input cancelled the
+        operation, the frame will be destroyed and the application will exit.
+        """
+        if self._docManager.Clear(not event.CanVeto()):
+            self.Destroy()
+        else:
+            event.Veto()
+
+
+class DocMDIChildFrame(wx.MDIChildFrame):
+    """
+    The wxDocMDIChildFrame class provides a default frame for displaying
+    documents on separate windows. This class can only be used for MDI child
+    frames.
+
+    The class is part of the document/view framework supported by wxWindows,
+    and cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate
+    classes.
+    """
+
+
+    def __init__(self, doc, view, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
+        """
+        Constructor.  Note that the event table must be rebuilt for the
+        frame since the EvtHandler is not virtual.
+        """
+        wx.MDIChildFrame.__init__(self, frame, id, title, pos, size, style, name)
+        self._childDocument = doc
+        self._childView = view
+        if view:
+            view.SetFrame(self)
+        # self.Create(doc, view, frame, id, title, pos, size, style, name)
+        self._activeEvent = None
+        self._activated = 0
+        wx.EVT_ACTIVATE(self, self.OnActivate)
+        wx.EVT_CLOSE(self, self.OnCloseWindow)
+
+        if frame:  # wxBug: For some reason the EVT_ACTIVATE event is not getting triggered for the first mdi client window that is opened so we have to do it manually
+            mdiChildren = filter(lambda x: isinstance(x, wx.MDIChildFrame), frame.GetChildren())
+            if len(mdiChildren) == 1:
+                self.Activate()
+
+
+##    # Couldn't get this to work, but seems to work fine with single stage construction
+##    def Create(self, doc, view, frame, id, title, pos, size, style, name):
+##        self._childDocument = doc
+##        self._childView = view
+##        if wx.MDIChildFrame.Create(self, frame, id, title, pos, size, style, name):
+##            if view:
+##                view.SetFrame(self)
+##                return True
+##        return False
+
+
+
+    def Activate(self):  # Need this in case there are embedded sash windows and such, OnActivate is not getting called
+        """
+        Activates the current view.
+        """
+        if self._childView:
+            self._childView.Activate(True)
+
+
+    def ProcessEvent(event):
+        """
+        Processes an event, searching event tables and calling zero or more
+        suitable event handler function(s).  Note that the ProcessEvent
+        method is called from the wxPython docview framework directly since
+        wxPython does not have a virtual ProcessEvent function.
+        """
+        if self._activeEvent == event:
+            return False
+
+        self._activeEvent = event  # Break recursion loops
+
+        if self._childView:
+            self._childView.Activate(True)
+
+        if not self._childView or not self._childView.ProcessEvent(event):
+            if not isinstance(event, wx.CommandEvent) or not self.GetParent() or not self.GetParent().ProcessEvent(event):
+                ret = False
+            else:
+                ret = True
+        else:
+            ret = True
+
+        self._activeEvent = None
+        return ret
+
+
+    def OnActivate(self, event):
+        """
+        Sets the currently active view to be the frame's view. You may need to
+        override (but still call) this function in order to set the keyboard
+        focus for your subwindow.
+        """
+        if self._activated != 0:
+            return True
+        self._activated += 1
+        wx.MDIChildFrame.Activate(self)
+        if event.GetActive() and self._childView:
+            self._childView.Activate(event.GetActive())
+        self._activated = 0
+
+    def OnCloseWindow(self, event):
+        """
+        Closes and deletes the current view and document.
+        """
+        if self._childView:
+            ans = False
+            if not event.CanVeto():
+                ans = True
+            else:
+                ans = self._childView.Close(deleteWindow = False)
+
+            if ans:
+                self._childView.Activate(False)
+                self._childView.Destroy()
+                self._childView = None
+                if self._childDocument:
+                    self._childDocument.Destroy()  # This isn't in the wxWindows codebase but the document needs to be disposed of somehow
+                self._childDocument = None
+                self.Destroy()
+            else:
+                event.Veto()
+        else:
+            event.Veto()
+
+
+    def GetDocument(self):
+        """
+        Returns the document associated with this frame.
+        """
+        return self._childDocument
+
+
+    def SetDocument(self, document):
+        """
+        Sets the document for this frame.
+        """
+        self._childDocument = document
+
+
+    def GetView(self):
+        """
+        Returns the view associated with this frame.
+        """
+        return self._childView
+
+
+    def SetView(self, view):
+        """
+        Sets the view for this frame.
+        """
+        self._childView = view
+
+
+class DocPrintout(wx.Printout):
+    """
+    DocPrintout is a default Printout that prints the first page of a document
+    view.
+    """
+
+
+    def __init__(self, view, title = "Printout"):
+        """
+        Constructor.
+        """
+        wx.Printout.__init__(self)
+        self._printoutView = view
+
+
+    def GetView(self):
+        """
+        Returns the DocPrintout's view.
+        """
+        return self._printoutView
+
+
+    def OnPrintPage(self, page):
+        """
+        Prints the first page of the view.
+        """
+        dc = self.GetDC()
+        ppiScreenX, ppiScreenY = self.GetPPIScreen()
+        ppiPrinterX, ppiPrinterY = self.GetPPIPrinter()
+        scale = ppiPrinterX/ppiScreenX
+        w, h = dc.GetSize()
+        pageWidth, pageHeight = self.GetPageSizePixels()
+        overallScale = scale * w / pageWidth
+        dc.SetUserScale(overallScale, overallScale)
+        if self._printoutView:
+            self._printoutView.OnDraw(dc)
+        return True
+
+
+    def HasPage(self, pageNum):
+        """
+        Indicates that the DocPrintout only has a single page.
+        """
+        return pageNum == 1
+
+
+    def OnBeginDocument(self, startPage, endPage):
+        """
+        Not quite sure why this was overridden, but it was in wxWindows! :)
+        """
+        if not wx.Printout.base_OnBeginDocument(self, startPage, endPage):
+            return False
+        return True
+
+
+    def GetPageInfo(self):
+        """
+        Indicates that the DocPrintout only has a single page.
+        """
+        minPage = 1
+        maxPage = 1
+        selPageFrom = 1
+        selPageTo = 1
+        return (minPage, maxPage, selPageFrom, selPageTo)
+
+
+#----------------------------------------------------------------------
+# Command Classes
+#----------------------------------------------------------------------
+
+class Command(wx.Object):
+    """
+    wxCommand is a base class for modelling an application command, which is
+    an action usually performed by selecting a menu item, pressing a toolbar
+    button or any other means provided by the application to change the data
+    or view.
+    """
+
+
+    def __init__(self, canUndo = False, name = None):
+        """
+        Constructor. wxCommand is an abstract class, so you will need to
+        derive a new class and call this constructor from your own constructor.
+
+        canUndo tells the command processor whether this command is undo-able.
+        You can achieve the same functionality by overriding the CanUndo member
+        function (if for example the criteria for undoability is context-
+        dependent).
+
+        name must be supplied for the command processor to display the command
+        name in the application's edit menu.
+        """
+        self._canUndo = canUndo
+        self._name = name
+
+
+    def CanUndo(self):
+        """
+        Returns true if the command can be undone, false otherwise.
+        """
+        return self._canUndo
+
+
+    def GetName(self):
+        """
+        Returns the command name.
+        """
+        return self._name
+
+
+    def Do(self):
+        """
+        Override this member function to execute the appropriate action when
+        called. Return true to indicate that the action has taken place, false
+        otherwise. Returning false will indicate to the command processor that
+        the action is not undoable and should not be added to the command
+        history.
+        """
+        return True
+
+
+    def Undo(self):
+        """
+        Override this member function to un-execute a previous Do. Return true
+        to indicate that the action has taken place, false otherwise. Returning
+        false will indicate to the command processor that the action is not
+        redoable and no change should be made to the command history.
+
+        How you implement this command is totally application dependent, but
+        typical strategies include:
+
+        Perform an inverse operation on the last modified piece of data in the
+        document. When redone, a copy of data stored in command is pasted back
+        or some operation reapplied. This relies on the fact that you know the
+        ordering of Undos; the user can never Undo at an arbitrary position in
+        he command history.
+
+        Restore the entire document state (perhaps using document
+        transactioning). Potentially very inefficient, but possibly easier to
+        code if the user interface and data are complex, and an 'inverse
+        execute' operation is hard to write.
+        """
+        return True
+
+
+class CommandProcessor(wx.Object):
+    """
+    wxCommandProcessor is a class that maintains a history of wxCommands, with
+    undo/redo functionality built-in. Derive a new class from this if you want
+    different behaviour.
+    """
+
+
+    def __init__(self, maxCommands = -1):
+        """
+        Constructor.  maxCommands may be set to a positive integer to limit
+        the number of commands stored to it, otherwise (and by default) the
+        list of commands can grow arbitrarily.
+        """
+        self._maxCommands = maxCommands
+        self._editMenu = None
+        self._undoAccelerator = _("Ctrl+Z")
+        self._redoAccelerator = _("Ctrl+Y")
+        self.ClearCommands()
+
+
+    def _GetCurrentCommand(self):
+        if len(self._commands) == 0:
+            return None
+        else:
+            return self._commands[-1]
+
+
+    def _GetCurrentRedoCommand(self):
+        if len(self._redoCommands) == 0:
+            return None
+        else:
+            return self._redoCommands[-1]
+
+
+    def GetMaxCommands(self):
+        """
+        Returns the maximum number of commands that the command processor
+        stores.
+
+        """
+        return self._maxCommands
+
+
+    def GetCommands(self):
+        """
+        Returns the list of commands.
+        """
+        return self._commands
+
+
+    def ClearCommands(self):
+        """
+        Deletes all the commands in the list and sets the current command
+        pointer to None.
+        """
+        self._commands = []
+        self._redoCommands = []
+
+
+    def GetEditMenu(self):
+        """
+        Returns the edit menu associated with the command processor.
+        """
+        return self._editMenu
+
+
+    def SetEditMenu(self, menu):
+        """
+        Tells the command processor to update the Undo and Redo items on this
+        menu as appropriate. Set this to NULL if the menu is about to be
+        destroyed and command operations may still be performed, or the
+        command processor may try to access an invalid pointer.
+        """
+        self._editMenu = menu
+
+
+    def GetUndoAccelerator(self):
+        """
+        Returns the string that will be appended to the Undo menu item.
+        """
+        return self._undoAccelerator
+
+
+    def SetUndoAccelerator(self, accel):
+        """
+        Sets the string that will be appended to the Redo menu item.
+        """
+        self._undoAccelerator = accel
+
+
+    def GetRedoAccelerator(self):
+        """
+        Returns the string that will be appended to the Redo menu item.
+        """
+        return self._redoAccelerator
+
+
+    def SetRedoAccelerator(self, accel):
+        """
+        Sets the string that will be appended to the Redo menu item.
+        """
+        self._redoAccelerator = accel
+
+
+    def SetEditMenu(self, menu):
+        """
+        Tells the command processor to update the Undo and Redo items on this
+        menu as appropriate. Set this to NULL if the menu is about to be
+        destroyed and command operations may still be performed, or the
+        command processor may try to access an invalid pointer.
+        """
+        self._editMenu = menu
+
+
+    def SetMenuStrings(self):
+        """
+        Sets the menu labels according to the currently set menu and the
+        current command state.
+        """
+        if self.GetEditMenu() != None:
+            undoCommand = self._GetCurrentCommand()
+            redoCommand = self._GetCurrentRedoCommand()
+            undoItem = self.GetEditMenu().FindItemById(wx.ID_UNDO)
+            redoItem = self.GetEditMenu().FindItemById(wx.ID_REDO)
+            if self.GetUndoAccelerator():
+                undoAccel = '\t' + self.GetUndoAccelerator()
+            else:
+                undoAccel = ''
+            if self.GetRedoAccelerator():
+                redoAccel = '\t' + self.GetRedoAccelerator()
+            else:
+                redoAccel = ''
+            if undoCommand and undoItem and undoCommand.CanUndo():
+                undoItem.SetText(_("Undo ") + undoCommand.GetName() + undoAccel)
+            #elif undoCommand and not undoCommand.CanUndo():
+            #    undoItem.SetText(_("Can't Undo") + undoAccel)
+            else:
+                undoItem.SetText(_("Undo" + undoAccel))
+            if redoCommand and redoItem:
+                redoItem.SetText(_("Redo ") + redoCommand.GetName() + redoAccel)
+            else:
+                redoItem.SetText(_("Redo") + redoAccel)
+
+
+    def CanUndo(self):
+        """
+        Returns true if the currently-active command can be undone, false
+        otherwise.
+        """
+        if self._GetCurrentCommand() == None:
+            return False
+        return self._GetCurrentCommand().CanUndo()
+
+
+    def CanRedo(self):
+        """
+        Returns true if the currently-active command can be redone, false
+        otherwise.
+        """
+        return self._GetCurrentRedoCommand() != None
+
+
+    def Submit(self, command, storeIt = True):
+        """
+        Submits a new command to the command processor. The command processor
+        calls wxCommand::Do to execute the command; if it succeeds, the
+        command is stored in the history list, and the associated edit menu
+        (if any) updated appropriately. If it fails, the command is deleted
+        immediately. Once Submit has been called, the passed command should
+        not be deleted directly by the application.
+
+        storeIt indicates whether the successful command should be stored in
+        the history list.
+        """
+        done = command.Do()
+        if done and storeIt:
+            self._commands.append(command)
+        if self._maxCommands > -1:
+            if len(self._commands) > self._maxCommands:
+                del self._commands[0]
+        return done
+
+
+    def Redo(self):
+        """
+        Redoes the command just undone.
+        """
+        cmd = self._GetCurrentRedoCommand()
+        if not cmd:
+            return False
+        done = cmd.Do()
+        if done:
+            self._commands.append(self._redoCommands.pop())
+        return done
+
+
+    def Undo(self):
+        """
+        Undoes the command just executed.
+        """
+        cmd = self._GetCurrentCommand()
+        if not cmd:
+            return False
+        done = cmd.Undo()
+        if done:
+            self._redoCommands.append(self._commands.pop())
+        return done
+
+