X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/74b8945829b602ebeae29f0237fbb8ff3f041f87..db679b8c836e69c111cdc31e62cf92cebe4f938f:/wxPython/wx/lib/docview.py diff --git a/wxPython/wx/lib/docview.py b/wxPython/wx/lib/docview.py index aad8359e14..2dd76d012a 100644 --- a/wxPython/wx/lib/docview.py +++ b/wxPython/wx/lib/docview.py @@ -6,7 +6,7 @@ # # Created: 5/15/03 # CVS-ID: $Id$ -# Copyright: (c) 2003-2004 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al) +# Copyright: (c) 2003-2005 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al) # License: wxWindows license #---------------------------------------------------------------------------- @@ -76,26 +76,31 @@ 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. + + Note this wxPython version also keeps track of the modification date of the + document and if it changes on disk outside of the application, we will warn the + user before saving to avoid clobbering the file. """ - def __init__(self, parent = None): + 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._writeable = True self._documentTitle = None self._documentFile = None self._documentTypeName = None self._documentModified = False + self._documentModificationDate = None self._documentViews = [] @@ -166,7 +171,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. @@ -210,6 +215,24 @@ class Document(wx.EvtHandler): self._documentModified = modify + def SetDocumentModificationDate(self): + """ + Saves the file's last modification date. + This is used to check if the file has been modified outside of the application. + This method has been added to wxPython and is not in wxWindows. + """ + self._documentModificationDate = os.path.getmtime(self.GetFilename()) + + + def GetDocumentModificationDate(self): + """ + Returns the file's modification date when it was loaded from disk. + This is used to check if the file has been modified outside of the application. + This method has been added to wxPython and is not in wxWindows. + """ + return self._documentModificationDate + + def GetViews(self): """ Returns the list whose elements are the views on the document. @@ -334,9 +357,26 @@ class Document(wx.EvtHandler): 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: + if not self.IsModified(): # and self._savedYet: This was here, but if it is not modified who cares if it hasn't been saved yet? return True + """ check for file modification outside of application """ + if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate(): + msgTitle = wx.GetApp().GetAppName() + if not msgTitle: + msgTitle = _("Application") + res = wx.MessageBox(_("'%s' has been modified outside of %s. Overwrite '%s' with current changes?") % (self.GetPrintableName(), msgTitle, self.GetPrintableName()), + msgTitle, + wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION, + self.GetDocumentWindow()) + + if res == wx.NO: + return True + elif res == wx.YES: + pass + else: # elif res == wx.CANCEL: + return False + if not self._documentFile or not self._savedYet: return self.SaveAs() return self.OnSaveDocument(self._documentFile) @@ -416,6 +456,7 @@ class Document(wx.EvtHandler): fileObject = file(filename, 'w') self.SaveObject(fileObject) + fileObject.close() if backupFilename: os.remove(backupFilename) @@ -424,6 +465,7 @@ class Document(wx.EvtHandler): if backupFilename: os.remove(filename) os.rename(backupFilename, filename) + self.SetDocumentModificationDate() wx.MessageBox("Could not save '%s'. %s" % (FileNameFromPath(filename), sys.exc_value), msgTitle, @@ -433,6 +475,7 @@ class Document(wx.EvtHandler): 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() @@ -467,6 +510,7 @@ class Document(wx.EvtHandler): self.SetFilename(filename, True) self.Modify(False) + self.SetDocumentModificationDate() self.SetDocumentSaved(True) self.UpdateAllViews() return True @@ -548,6 +592,24 @@ class Document(wx.EvtHandler): if not self.IsModified(): return True + """ check for file modification outside of application """ + if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate(): + msgTitle = wx.GetApp().GetAppName() + if not msgTitle: + msgTitle = _("Warning") + res = wx.MessageBox(_("'%s' has been modified outside of %s. Overwrite '%s' with current changes?") % (self.GetPrintableName(), msgTitle, 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 wx.lib.docview.Document.Save(self) + else: # elif res == wx.CANCEL: + return False + msgTitle = wx.GetApp().GetAppName() if not msgTitle: msgTitle = _("Warning") @@ -646,6 +708,29 @@ class Document(wx.EvtHandler): view.OnChangeFilename() + def GetWriteable(self): + """ + Returns true if the document can be written to its accociated file path. + This method has been added to wxPython and is not in wxWindows. + """ + if not self._writeable: + return False + if not self._documentFile: # Doesn't exist, do a save as + return True + else: + return os.access(self._documentFile, os.W_OK) + + + def SetWriteable(self, writeable): + """ + Set to False if the document can not be saved. This will disable the ID_SAVE_AS + event and is useful for custom documents that should not be saveable. The ID_SAVE + event can be disabled by never Modifying the document. This method has been added + to wxPython and is not in wxWindows. + """ + self._writeable = writeable + + class View(wx.EvtHandler): """ The view class can be used to model the viewing and editing component of @@ -753,7 +838,7 @@ class View(wx.EvtHandler): else: return else: - if appName and not isinstance(self.GetFrame(), DocMDIChildFrame): # Don't need appname in title for MDI + if appName and isinstance(self.GetFrame(), DocChildFrame): # Only need app name in title for SDI title = appName + _(" - ") else: title = '' @@ -792,7 +877,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. @@ -803,7 +888,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 @@ -819,7 +904,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 @@ -900,7 +985,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 @@ -1157,7 +1242,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. @@ -1230,7 +1315,7 @@ class DocManager(wx.EvtHandler): return self._flags - def CloseDocument(self, doc, force = True): + def CloseDocument(self, doc, force=True): """ Closes the specified document. """ @@ -1242,7 +1327,7 @@ class DocManager(wx.EvtHandler): return False - def CloseDocuments(self, force = True): + def CloseDocuments(self, force=True): """ Closes all currently opened documents. """ @@ -1253,7 +1338,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. @@ -1306,7 +1391,7 @@ class DocManager(wx.EvtHandler): """ return self.CloseDocuments(force = False) - + def OnFileNew(self, event): """ Creates a new document and reads in the selected file. @@ -1478,7 +1563,7 @@ class DocManager(wx.EvtHandler): """ Updates the user interface for the File Save As command. """ - event.Enable(self.GetCurrentDocument() != None) + event.Enable(self.GetCurrentDocument() != None and self.GetCurrentDocument().GetWriteable()) def OnUpdateUndo(self, event): @@ -1653,7 +1738,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: @@ -1718,6 +1803,24 @@ class DocManager(wx.EvtHandler): if self.GetFlags() & DOC_OPEN_ONCE: for document in self._docs: if document.GetFilename() == path: + """ check for file modification outside of application """ + if os.path.exists(path) and os.path.getmtime(path) != document.GetDocumentModificationDate(): + 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(): firstView.GetFrame().SetFocus() # Not in wxWindows code but useful nonetheless @@ -1740,7 +1843,7 @@ class DocManager(wx.EvtHandler): return None - def CreateView(self, document, flags = 0): + 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 @@ -1901,7 +2004,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. @@ -2009,7 +2112,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. @@ -2057,7 +2160,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. """ @@ -2127,7 +2230,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. """ @@ -2174,7 +2277,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. @@ -2284,7 +2387,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. @@ -2430,7 +2533,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. @@ -2540,7 +2643,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. @@ -2683,7 +2786,7 @@ class DocPrintout(wx.Printout): """ - def __init__(self, view, title = "Printout"): + def __init__(self, view, title="Printout"): """ Constructor. """ @@ -2829,7 +2932,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 @@ -2984,7 +3087,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