X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/5088276afa09aa8fa540f670d6d5b8ef53957a8f..6231770f8935b3a2c5e27a32b9103287076d9191:/wxPython/wx/lib/docview.py diff --git a/wxPython/wx/lib/docview.py b/wxPython/wx/lib/docview.py index e99799ff3d..8f85b4be2f 100644 --- a/wxPython/wx/lib/docview.py +++ b/wxPython/wx/lib/docview.py @@ -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 @@ -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") @@ -436,6 +452,7 @@ class Document(wx.EvtHandler): backupFilename = None fileObject = None + copied = False try: # if current file exists, move it to a safe place temporarily if os.path.exists(filename): @@ -453,7 +470,8 @@ 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) @@ -470,11 +488,9 @@ class Document(wx.EvtHandler): if fileObject: fileObject.close() # file is still open, close it, need to do this before removal - # save failed, restore old file - if backupFilename: - os.remove(filename) - os.rename(backupFilename, filename) - self.SetDocumentModificationDate() + # 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, @@ -482,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() @@ -526,9 +542,9 @@ class Document(wx.EvtHandler): self.GetDocumentWindow()) return False + self.SetDocumentModificationDate() self.SetFilename(filename, True) self.Modify(False) - self.SetDocumentModificationDate() self.SetDocumentSaved(True) self.UpdateAllViews() return True @@ -611,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") @@ -679,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) @@ -839,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): """ @@ -1015,7 +1039,7 @@ class DocTemplate(wx.Object): string will be displayed in the file filter list of Windows file selectors. - filter is an appropriate file filter such as *.txt. + filter is an appropriate file filter such as \*.txt. dir is the default directory to use for file selectors. @@ -1192,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 @@ -1247,14 +1281,11 @@ class DocTemplate(wx.Object): Returns True if the path's extension matches one of this template's file filter extensions. """ -## print "*** path", path -## if "*.*" in self.GetFileFilter(): -## return True -## 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): @@ -1805,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: @@ -1820,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: @@ -1850,7 +1884,7 @@ class DocManager(wx.EvtHandler): for document in self._docs: if document.GetFilename() and os.path.normcase(document.GetFilename()) == os.path.normcase(path): """ check for file modification outside of application """ - if os.path.exists(path) and os.path.getmtime(path) != document.GetDocumentModificationDate(): + if not document.IsDocumentModificationDateCorrect(): msgTitle = wx.GetApp().GetAppName() if not msgTitle: msgTitle = _("Warning") @@ -1868,7 +1902,12 @@ class DocManager(wx.EvtHandler): 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) @@ -1881,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 @@ -2120,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 (%s)|%s|%s|Any (*.*) | *.*") % (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): @@ -2778,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. @@ -2793,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: @@ -2831,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 @@ -2877,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. @@ -3152,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]