]> git.saurik.com Git - wxWidgets.git/blobdiff - wxPython/wx/lib/docview.py
Use MustHaveApp for wx.RendererNative.Get and others
[wxWidgets.git] / wxPython / wx / lib / docview.py
index a945a14969cfe801078d44069f76f13205842f72..3d24b224d3f8c7fa384ec73cf2248392c02b302d 100644 (file)
@@ -6,13 +6,14 @@
 #
 # Created:      5/15/03
 # CVS-ID:       $Id$
-# Copyright:    (c) 2003-2005 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al)
+# Copyright:    (c) 2003-2006 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al)
 # License:      wxWindows license
 #----------------------------------------------------------------------------
 
 
 import os
 import os.path
+import shutil
 import wx
 import sys
 _ = wx.GetTranslation
@@ -27,10 +28,12 @@ DOC_MDI = 2
 DOC_NEW = 4
 DOC_SILENT = 8
 DOC_OPEN_ONCE = 16
+DOC_NO_VIEW = 32
 DEFAULT_DOCMAN_FLAGS = DOC_SDI & DOC_OPEN_ONCE
 
 TEMPLATE_VISIBLE = 1
 TEMPLATE_INVISIBLE = 2
+TEMPLATE_NO_CREATE = (4 | TEMPLATE_VISIBLE)
 DEFAULT_TEMPLATE_FLAGS = TEMPLATE_VISIBLE
 
 MAX_FILE_HISTORY = 9
@@ -83,7 +86,7 @@ class Document(wx.EvtHandler):
     """
 
 
-    def __init__(self, parent = None):
+    def __init__(self, parent=None):
         """
         Constructor.  Define your own default constructor to initialize
         application-specific data.
@@ -171,7 +174,7 @@ class Document(wx.EvtHandler):
         return self._savedYet
 
 
-    def SetDocumentSaved(self, saved = True):
+    def SetDocumentSaved(self, saved=True):
         """
         Sets whether the document has been saved.  This method has been
         added to wxPython and is not in wxWindows.
@@ -211,8 +214,10 @@ class Document(wx.EvtHandler):
         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).
+        This method has been extended to notify its views that the dirty flag has changed.
         """
         self._documentModified = modify
+        self.UpdateAllViews(hint=("modify", self, self._documentModified))
 
 
     def SetDocumentModificationDate(self):
@@ -233,6 +238,16 @@ class Document(wx.EvtHandler):
         return self._documentModificationDate
 
 
+    def IsDocumentModificationDateCorrect(self):
+        """
+        Returns False if the file has been modified outside of the application.
+        This method has been added to wxPython and is not in wxWindows.
+        """
+        if not os.path.exists(self.GetFilename()):  # document must be in memory only and can't be out of date
+            return True
+        return self._documentModificationDate == os.path.getmtime(self.GetFilename())
+
+
     def GetViews(self):
         """
         Returns the list whose elements are the views on the document.
@@ -268,6 +283,7 @@ class Document(wx.EvtHandler):
         Destructor. Removes itself from the document manager.
         """
         self.DeleteContents()
+        self._documentModificationDate = None
         if self.GetDocumentManager():
             self.GetDocumentManager().RemoveDocument(self)
         wx.EvtHandler.Destroy(self)
@@ -361,7 +377,7 @@ class Document(wx.EvtHandler):
             return True
 
         """ check for file modification outside of application """
-        if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate():
+        if not self.IsDocumentModificationDateCorrect():
             msgTitle = wx.GetApp().GetAppName()
             if not msgTitle:
                 msgTitle = _("Application")
@@ -435,6 +451,8 @@ class Document(wx.EvtHandler):
             msgTitle = _("File Error")
 
         backupFilename = None
+        fileObject = None
+        copied = False
         try:
             # if current file exists, move it to a safe place temporarily
             if os.path.exists(filename):
@@ -452,19 +470,27 @@ class Document(wx.EvtHandler):
                 while os.path.exists(backupFilename):
                     i += 1
                     backupFilename = "%s.bak%s" % (filename, i)
-                os.rename(filename, backupFilename)
+                shutil.copy(filename, backupFilename)
+                copied = True
 
             fileObject = file(filename, 'w')
             self.SaveObject(fileObject)
-
+            fileObject.close()
+            fileObject = None
+            
             if backupFilename:
                 os.remove(backupFilename)
         except:
-            # save failed, restore old file
-            if backupFilename:
-                os.remove(filename)
-                os.rename(backupFilename, filename)
-                self.SetDocumentModificationDate()
+            # for debugging purposes
+            import traceback
+            traceback.print_exc()
+
+            if fileObject:
+                fileObject.close()  # file is still open, close it, need to do this before removal 
+
+            # save failed, remove copied file
+            if backupFilename and copied:
+                os.remove(backupFilename)
 
             wx.MessageBox("Could not save '%s'.  %s" % (FileNameFromPath(filename), sys.exc_value),
                           msgTitle,
@@ -472,9 +498,9 @@ class Document(wx.EvtHandler):
                           self.GetDocumentWindow())
             return False
 
+        self.SetDocumentModificationDate()
         self.SetFilename(filename, True)
         self.Modify(False)
-        self.SetDocumentModificationDate()
         self.SetDocumentSaved(True)
         #if wx.Platform == '__WXMAC__':  # Not yet implemented in wxPython
         #    wx.FileName(file).MacSetDefaultTypeAndCreator()
@@ -500,16 +526,25 @@ class Document(wx.EvtHandler):
         fileObject = file(filename, 'r')
         try:
             self.LoadObject(fileObject)
+            fileObject.close()
+            fileObject = None
         except:
+            # for debugging purposes
+            import traceback
+            traceback.print_exc()
+
+            if fileObject:
+                fileObject.close()  # file is still open, close it 
+
             wx.MessageBox("Could not open '%s'.  %s" % (FileNameFromPath(filename), sys.exc_value),
                           msgTitle,
                           wx.OK | wx.ICON_EXCLAMATION,
                           self.GetDocumentWindow())
             return False
 
+        self.SetDocumentModificationDate()
         self.SetFilename(filename, True)
         self.Modify(False)
-        self.SetDocumentModificationDate()
         self.SetDocumentSaved(True)
         self.UpdateAllViews()
         return True
@@ -592,7 +627,7 @@ class Document(wx.EvtHandler):
             return True
 
         """ check for file modification outside of application """
-        if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate():
+        if not self.IsDocumentModificationDateCorrect():
             msgTitle = wx.GetApp().GetAppName()
             if not msgTitle:
                 msgTitle = _("Warning")
@@ -660,8 +695,10 @@ class Document(wx.EvtHandler):
         """
         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.
+        supply additional behaviour when the document is opened with Open.
         """
+        if flags & DOC_NO_VIEW:
+            return True
         return self.GetDocumentTemplate().CreateView(self, flags)
 
 
@@ -820,8 +857,14 @@ class View(wx.EvtHandler):
         unused but may in future contain application-specific information for
         making updating more efficient.
         """
-        pass
-
+        if hint:
+            if hint[0] == "modify":  # if dirty flag changed, update the view's displayed title
+                frame = self.GetFrame()
+                if frame and hasattr(frame, "OnTitleIsModified"):
+                    frame.OnTitleIsModified()
+                    return True
+        return False
+        
 
     def OnChangeFilename(self):
         """
@@ -876,7 +919,7 @@ class View(wx.EvtHandler):
         self._viewTypeName = name
 
 
-    def Close(self, deleteWindow = True):
+    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.
@@ -887,7 +930,7 @@ class View(wx.EvtHandler):
             return False
 
 
-    def Activate(self, activate = True):
+    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
@@ -903,7 +946,7 @@ class View(wx.EvtHandler):
             self.GetDocumentManager().ActivateView(self, activate)
 
 
-    def OnClose(self, deleteWindow = True):
+    def OnClose(self, deleteWindow=True):
         """
         Implements closing behaviour. The default implementation calls
         wxDocument.Close to close the associated document. Does not delete the
@@ -944,7 +987,7 @@ class View(wx.EvtHandler):
 
         Override to return an instance of a class other than wxDocPrintout.
         """
-        return DocPrintout(self)
+        return DocPrintout(self, self.GetDocument().GetPrintableName())
 
 
     def GetFrame(self):
@@ -984,7 +1027,7 @@ class DocTemplate(wx.Object):
     """
 
 
-    def __init__(self, manager, description, filter, dir, ext, docTypeName, viewTypeName, docType, viewType, flags = DEFAULT_TEMPLATE_FLAGS, icon = None):
+    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
@@ -1173,6 +1216,16 @@ class DocTemplate(wx.Object):
         return (self._flags & TEMPLATE_VISIBLE) == TEMPLATE_VISIBLE
 
 
+    def IsNewable(self):
+        """
+        Returns true if the document template can be shown in "New" dialogs,
+        false otherwise.
+        
+        This method has been added to wxPython and is not in wxWindows.
+        """
+        return (self._flags & TEMPLATE_NO_CREATE) != TEMPLATE_NO_CREATE
+        
+
     def GetDocumentName(self):
         """
         Returns the document type name, as passed to the document template
@@ -1230,8 +1283,9 @@ class DocTemplate(wx.Object):
         """
         ext = FindExtension(path)
         if not ext: return False
-        return ext in self.GetFileFilter()
-        # return self.GetDefaultExtension() == FindExtension(path)
+        
+        extList = self.GetFileFilter().replace('*','').split(';')
+        return ext in extList
 
 
 class DocManager(wx.EvtHandler):
@@ -1241,7 +1295,7 @@ class DocManager(wx.EvtHandler):
     classes.
     """
 
-    def __init__(self, flags = DEFAULT_DOCMAN_FLAGS, initialize = True):
+    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.
@@ -1314,7 +1368,7 @@ class DocManager(wx.EvtHandler):
         return self._flags
 
 
-    def CloseDocument(self, doc, force = True):
+    def CloseDocument(self, doc, force=True):
         """
         Closes the specified document.
         """
@@ -1326,7 +1380,7 @@ class DocManager(wx.EvtHandler):
         return False
 
 
-    def CloseDocuments(self, force = True):
+    def CloseDocuments(self, force=True):
         """
         Closes all currently opened documents.
         """
@@ -1337,7 +1391,7 @@ class DocManager(wx.EvtHandler):
         return True
 
 
-    def Clear(self, force = True):
+    def Clear(self, force=True):
         """
         Closes all currently opened document by callling CloseDocuments and
         clears the document manager's templates.
@@ -1390,7 +1444,7 @@ class DocManager(wx.EvtHandler):
         """
         return self.CloseDocuments(force = False)
 
-
+    
     def OnFileNew(self, event):
         """
         Creates a new document and reads in the selected file.
@@ -1449,9 +1503,14 @@ class DocManager(wx.EvtHandler):
 
         printout = view.OnCreatePrintout()
         if printout:
-            pdd = wx.PrintDialogData()
+            if not hasattr(self, "printData"):
+                self.printData = wx.PrintData()
+                self.printData.SetPaperId(wx.PAPER_LETTER)
+            self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER)
+                
+            pdd = wx.PrintDialogData(self.printData)
             printer = wx.Printer(pdd)
-            printer.Print(view.GetFrame(), printout) # , True)
+            printer.Print(view.GetFrame(), printout)
 
 
     def OnPrintSetup(self, event):
@@ -1464,11 +1523,21 @@ class DocManager(wx.EvtHandler):
         else:
             parentWin = wx.GetApp().GetTopWindow()
 
-        data = wx.PrintDialogData()
+        if not hasattr(self, "printData"):
+            self.printData = wx.PrintData()
+            self.printData.SetPaperId(wx.PAPER_LETTER)
+            
+        data = wx.PrintDialogData(self.printData)
         printDialog = wx.PrintDialog(parentWin, data)
         printDialog.GetPrintDialogData().SetSetupDialog(True)
         printDialog.ShowModal()
-        # TODO: Confirm that we don't have to remember PrintDialogData
+        
+        # this makes a copy of the wx.PrintData instead of just saving
+        # a reference to the one inside the PrintDialogData that will
+        # be destroyed when the dialog is destroyed
+        self.printData = wx.PrintData(printDialog.GetPrintDialogData().GetPrintData())
+        
+        printDialog.Destroy()
 
 
     def OnPreview(self, event):
@@ -1482,13 +1551,22 @@ class DocManager(wx.EvtHandler):
 
         printout = view.OnCreatePrintout()
         if printout:
+            if not hasattr(self, "printData"):
+                self.printData = wx.PrintData()
+                self.printData.SetPaperId(wx.PAPER_LETTER)
+            self.printData.SetPrintMode(wx.PRINT_MODE_PREVIEW)
+                
+            data = wx.PrintDialogData(self.printData)
             # Pass two printout objects: for preview, and possible printing.
-            preview = wx.PrintPreview(printout, view.OnCreatePrintout())
+            preview = wx.PrintPreview(printout, view.OnCreatePrintout(), data)
+            if not preview.Ok():
+                wx.MessageBox(_("Unable to display print preview."))
+                return
             # 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.SetTitle(_("%s - %s - Preview") % (mimicFrame.GetTitle(), view.GetDocument().GetPrintableName()))
             frame.Initialize()
             frame.Show(True)
 
@@ -1574,7 +1652,7 @@ class DocManager(wx.EvtHandler):
         if doc and doc.GetCommandProcessor():
             doc.GetCommandProcessor().SetMenuStrings()
         else:
-            event.SetText(_("Undo") + '\t' + _('Ctrl+Z'))
+            event.SetText(_("&Undo\tCtrl+Z"))
 
 
     def OnUpdateRedo(self, event):
@@ -1586,7 +1664,7 @@ class DocManager(wx.EvtHandler):
         if doc and doc.GetCommandProcessor():
             doc.GetCommandProcessor().SetMenuStrings()
         else:
-            event.SetText(_("Redo") + '\t' + _('Ctrl+Y'))
+            event.SetText(_("&Redo\tCtrl+Y"))
 
 
     def OnUpdatePrint(self, event):
@@ -1737,7 +1815,7 @@ class DocManager(wx.EvtHandler):
             return False
 
 
-    def CreateDocument(self, path, flags = 0):
+    def CreateDocument(self, path, flags=0):
         """
         Creates a new document in a manner determined by the flags parameter,
         which can be:
@@ -1758,7 +1836,13 @@ class DocManager(wx.EvtHandler):
         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.
+        wxPython version supports the document manager's wx.lib.docview.DOC_OPEN_ONCE
+        and wx.lib.docview.DOC_NO_VIEW flag.
+        
+        if wx.lib.docview.DOC_OPEN_ONCE is present, trying to open the same file multiple 
+        times will just return the same document.
+        if wx.lib.docview.DOC_NO_VIEW is present, opening a file will generate the document,
+        but not generate a corresponding view.
         """
         templates = []
         for temp in self._templates:
@@ -1773,16 +1857,13 @@ class DocManager(wx.EvtHandler):
                return None
 
         if flags & DOC_NEW:
+            for temp in templates[:]:
+                if not temp.IsNewable():
+                    templates.remove(temp)
             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)
+            else:
+                temp = self.SelectDocumentType(templates)
             if temp:
                 newDoc = temp.CreateDocument(path, flags)
                 if newDoc:
@@ -1799,11 +1880,34 @@ class DocManager(wx.EvtHandler):
             temp, path = self.SelectDocumentPath(templates, path, flags)
 
         # Existing document
-        if self.GetFlags() & DOC_OPEN_ONCE:
+        if path and self.GetFlags() & DOC_OPEN_ONCE:
             for document in self._docs:
-                if document.GetFilename() == path:
+                if document.GetFilename() and os.path.normcase(document.GetFilename()) == os.path.normcase(path):
+                    """ check for file modification outside of application """
+                    if not document.IsDocumentModificationDateCorrect():
+                        msgTitle = wx.GetApp().GetAppName()
+                        if not msgTitle:
+                            msgTitle = _("Warning")
+                        shortName = document.GetPrintableName()
+                        res = wx.MessageBox(_("'%s' has been modified outside of %s.  Reload '%s' from file system?") % (shortName, msgTitle, shortName),
+                                            msgTitle,
+                                            wx.YES_NO | wx.ICON_QUESTION,
+                                            self.FindSuitableParent())
+                        if res == wx.YES:
+                           if not self.CloseDocument(document, False):
+                               wx.MessageBox(_("Couldn't reload '%s'.  Unable to close current '%s'.") % (shortName, shortName))
+                               return None
+                           return self.CreateDocument(path, flags)
+                        elif res == wx.NO:  # don't ask again
+                            document.SetDocumentModificationDate()
+
                     firstView = document.GetFirstView()
-                    if firstView and firstView.GetFrame():
+                    if not firstView and not (flags & DOC_NO_VIEW):
+                        document.GetDocumentTemplate().CreateView(document, flags)
+                        document.UpdateAllViews()
+                        firstView = document.GetFirstView()
+                        
+                    if firstView and firstView.GetFrame() and not (flags & DOC_NO_VIEW):
                         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)
@@ -1816,7 +1920,9 @@ class DocManager(wx.EvtHandler):
                 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.
+                    frame = newDoc.GetFirstView().GetFrame()
+                    if frame:
+                        frame.Destroy() # DeleteAllViews doesn't get rid of the frame, so we'll explicitly destroy it.
                     return None
                 self.AddFileToHistory(path)
             return newDoc
@@ -1824,7 +1930,7 @@ class DocManager(wx.EvtHandler):
         return None
 
 
-    def CreateView(self, document, flags = 0):
+    def CreateView(self, doc, 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
@@ -1985,7 +2091,7 @@ class DocManager(wx.EvtHandler):
             self._fileHistory.Save(config)
 
 
-    def FileHistoryAddFilesToMenu(self, menu = None):
+    def FileHistoryAddFilesToMenu(self, menu=None):
         """
         Appends the files in the history list, to all menus managed by the
         file history object.
@@ -2015,11 +2121,17 @@ class DocManager(wx.EvtHandler):
         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.
+        
+        Note this wxPython verson looks for and returns a default template if no specific template is found.
         """
+        default = None
         for temp in self._templates:
             if temp.FileMatchesTemplate(path):
                 return temp
-        return None
+                
+            if "*.*" in temp.GetFileFilter():
+                default = temp
+        return default
 
 
     def FindSuitableParent(self):
@@ -2049,41 +2161,32 @@ class DocManager(wx.EvtHandler):
         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
+            descr = _("All|*.*|%s") % 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)
-
+        dlg = wx.FileDialog(self.FindSuitableParent(),
+                               _("Select a File"),
+                               wildcard=descr,
+                               style=wx.OPEN|wx.FILE_MUST_EXIST|wx.CHANGE_DIR)
+        # dlg.CenterOnParent()  # wxBug: caused crash with wx.FileDialog
+        if dlg.ShowModal() == wx.ID_OK:
+            path = dlg.GetPath()
+        else:
+            path = None
+        dlg.Destroy()
+            
+        if path:  
             theTemplate = self.FindTemplateForPath(path)
             return (theTemplate, path)
-
-        return (None, None)
+        
+        return (None, None)           
 
 
     def OnOpenFileFailure(self):
@@ -2093,7 +2196,7 @@ class DocManager(wx.EvtHandler):
         pass
 
 
-    def SelectDocumentType(self, temps, sort = False):
+    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.
@@ -2141,7 +2244,7 @@ class DocManager(wx.EvtHandler):
         return templates[res]
 
 
-    def SelectViewType(self, temps, sort = False):
+    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.
         """
@@ -2211,7 +2314,7 @@ class DocManager(wx.EvtHandler):
             self._docs.remove(doc)
 
 
-    def ActivateView(self, view, activate = True, deleting = False):
+    def ActivateView(self, view, activate=True, deleting=False):
         """
         Sets the current view.
         """
@@ -2258,7 +2361,7 @@ class DocParentFrame(wx.Frame):
     classes.
     """
 
-    def __init__(self, manager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
+    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.
@@ -2368,7 +2471,7 @@ class DocChildFrame(wx.Frame):
     """
 
 
-    def __init__(self, doc, view, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
+    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.
@@ -2514,7 +2617,7 @@ class DocMDIParentFrame(wx.MDIParentFrame):
     """
 
 
-    def __init__(self, manager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
+    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.
@@ -2624,7 +2727,7 @@ class DocMDIChildFrame(wx.MDIChildFrame):
     """
 
 
-    def __init__(self, doc, view, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "frame"):
+    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.
@@ -2707,6 +2810,7 @@ class DocMDIChildFrame(wx.MDIChildFrame):
             self._childView.Activate(event.GetActive())
         self._activated = 0
 
+
     def OnCloseWindow(self, event):
         """
         Closes and deletes the current view and document.
@@ -2722,8 +2826,10 @@ class DocMDIChildFrame(wx.MDIChildFrame):
                 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
+                if self._childDocument:  # This isn't in the wxWindows codebase but the document needs to be disposed of somehow
+                    self._childDocument.DeleteContents()
+                    if self._childDocument.GetDocumentManager():
+                        self._childDocument.GetDocumentManager().RemoveDocument(self._childDocument)
                 self._childDocument = None
                 self.Destroy()
             else:
@@ -2760,6 +2866,28 @@ class DocMDIChildFrame(wx.MDIChildFrame):
         self._childView = view
 
 
+    def OnTitleIsModified(self):
+        """
+        Add/remove to the frame's title an indication that the document is dirty.
+        If the document is dirty, an '*' is appended to the title
+        This method has been added to wxPython and is not in wxWindows.
+        """
+        title = self.GetTitle()
+        if title:
+            if self.GetDocument().IsModified():
+                if title.endswith("*"):
+                    return
+                else:
+                    title = title + "*"
+                    self.SetTitle(title)
+            else:
+                if title.endswith("*"):
+                    title = title[:-1]
+                    self.SetTitle(title)                
+                else:
+                    return
+
+
 class DocPrintout(wx.Printout):
     """
     DocPrintout is a default Printout that prints the first page of a document
@@ -2767,11 +2895,11 @@ class DocPrintout(wx.Printout):
     """
 
 
-    def __init__(self, view, title = "Printout"):
+    def __init__(self, view, title="Printout"):
         """
         Constructor.
         """
-        wx.Printout.__init__(self)
+        wx.Printout.__init__(self, title)
         self._printoutView = view
 
 
@@ -2806,15 +2934,6 @@ class DocPrintout(wx.Printout):
         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.
@@ -2913,7 +3032,7 @@ class CommandProcessor(wx.Object):
     """
 
 
-    def __init__(self, maxCommands = -1):
+    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
@@ -3039,15 +3158,15 @@ class CommandProcessor(wx.Object):
             else:
                 redoAccel = ''
             if undoCommand and undoItem and undoCommand.CanUndo():
-                undoItem.SetText(_("Undo ") + undoCommand.GetName() + undoAccel)
+                undoItem.SetText(_("&Undo ") + undoCommand.GetName() + undoAccel)
             #elif undoCommand and not undoCommand.CanUndo():
             #    undoItem.SetText(_("Can't Undo") + undoAccel)
             else:
-                undoItem.SetText(_("Undo" + undoAccel))
+                undoItem.SetText(_("&Undo" + undoAccel))
             if redoCommand and redoItem:
-                redoItem.SetText(_("Redo ") + redoCommand.GetName() + redoAccel)
+                redoItem.SetText(_("&Redo ") + redoCommand.GetName() + redoAccel)
             else:
-                redoItem.SetText(_("Redo") + redoAccel)
+                redoItem.SetText(_("&Redo") + redoAccel)
 
 
     def CanUndo(self):
@@ -3068,7 +3187,7 @@ class CommandProcessor(wx.Object):
         return self._GetCurrentRedoCommand() != None
 
 
-    def Submit(self, command, storeIt = True):
+    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
@@ -3081,8 +3200,10 @@ class CommandProcessor(wx.Object):
         the history list.
         """
         done = command.Do()
-        if done and storeIt:
-            self._commands.append(command)
+        if done:
+            del self._redoCommands[:]
+            if storeIt:
+                self._commands.append(command)
         if self._maxCommands > -1:
             if len(self._commands) > self._maxCommands:
                 del self._commands[0]