]> git.saurik.com Git - wxWidgets.git/blob - wxPython/wx/lib/docview.py
Olly Betts' typo patch
[wxWidgets.git] / wxPython / wx / lib / docview.py
1 #----------------------------------------------------------------------------
2 # Name: docview.py
3 # Purpose: Port of the wxWindows docview classes
4 #
5 # Author: Peter Yared
6 #
7 # Created: 5/15/03
8 # CVS-ID: $Id$
9 # Copyright: (c) 2003-2005 ActiveGrid, Inc. (Port of wxWindows classes by Julian Smart et al)
10 # License: wxWindows license
11 #----------------------------------------------------------------------------
12
13
14 import os
15 import os.path
16 import wx
17 import sys
18 _ = wx.GetTranslation
19
20
21 #----------------------------------------------------------------------
22 # docview globals
23 #----------------------------------------------------------------------
24
25 DOC_SDI = 1
26 DOC_MDI = 2
27 DOC_NEW = 4
28 DOC_SILENT = 8
29 DOC_OPEN_ONCE = 16
30 DEFAULT_DOCMAN_FLAGS = DOC_SDI & DOC_OPEN_ONCE
31
32 TEMPLATE_VISIBLE = 1
33 TEMPLATE_INVISIBLE = 2
34 DEFAULT_TEMPLATE_FLAGS = TEMPLATE_VISIBLE
35
36 MAX_FILE_HISTORY = 9
37
38
39 #----------------------------------------------------------------------
40 # Convenience functions from wxWindows used in docview
41 #----------------------------------------------------------------------
42
43
44 def FileNameFromPath(path):
45 """
46 Returns the filename for a full path.
47 """
48 return os.path.split(path)[1]
49
50 def FindExtension(path):
51 """
52 Returns the extension of a filename for a full path.
53 """
54 return os.path.splitext(path)[1].lower()
55
56 def FileExists(path):
57 """
58 Returns True if the path exists.
59 """
60 return os.path.isfile(path)
61
62 def PathOnly(path):
63 """
64 Returns the path of a full path without the filename.
65 """
66 return os.path.split(path)[0]
67
68
69 #----------------------------------------------------------------------
70 # Document/View Classes
71 #----------------------------------------------------------------------
72
73
74 class Document(wx.EvtHandler):
75 """
76 The document class can be used to model an application's file-based data. It
77 is part of the document/view framework supported by wxWindows, and cooperates
78 with the wxView, wxDocTemplate and wxDocManager classes.
79
80 Note this wxPython version also keeps track of the modification date of the
81 document and if it changes on disk outside of the application, we will warn the
82 user before saving to avoid clobbering the file.
83 """
84
85
86 def __init__(self, parent=None):
87 """
88 Constructor. Define your own default constructor to initialize
89 application-specific data.
90 """
91 wx.EvtHandler.__init__(self)
92
93 self._documentParent = parent
94 self._documentTemplate = None
95 self._commandProcessor = None
96 self._savedYet = False
97 self._writeable = True
98
99 self._documentTitle = None
100 self._documentFile = None
101 self._documentTypeName = None
102 self._documentModified = False
103 self._documentModificationDate = None
104 self._documentViews = []
105
106
107 def ProcessEvent(self, event):
108 """
109 Processes an event, searching event tables and calling zero or more
110 suitable event handler function(s). Note that the ProcessEvent
111 method is called from the wxPython docview framework directly since
112 wxPython does not have a virtual ProcessEvent function.
113 """
114 return False
115
116
117 def GetFilename(self):
118 """
119 Gets the filename associated with this document, or "" if none is
120 associated.
121 """
122 return self._documentFile
123
124
125 def GetTitle(self):
126 """
127 Gets the title for this document. The document title is used for an
128 associated frame (if any), and is usually constructed by the framework
129 from the filename.
130 """
131 return self._documentTitle
132
133
134 def SetTitle(self, title):
135 """
136 Sets the title for this document. The document title is used for an
137 associated frame (if any), and is usually constructed by the framework
138 from the filename.
139 """
140 self._documentTitle = title
141
142
143 def GetDocumentName(self):
144 """
145 The document type name given to the wxDocTemplate constructor,
146 copied to this document when the document is created. If several
147 document templates are created that use the same document type, this
148 variable is used in wxDocManager::CreateView to collate a list of
149 alternative view types that can be used on this kind of document.
150 """
151 return self._documentTypeName
152
153
154 def SetDocumentName(self, name):
155 """
156 Sets he document type name given to the wxDocTemplate constructor,
157 copied to this document when the document is created. If several
158 document templates are created that use the same document type, this
159 variable is used in wxDocManager::CreateView to collate a list of
160 alternative view types that can be used on this kind of document. Do
161 not change the value of this variable.
162 """
163 self._documentTypeName = name
164
165
166 def GetDocumentSaved(self):
167 """
168 Returns True if the document has been saved. This method has been
169 added to wxPython and is not in wxWindows.
170 """
171 return self._savedYet
172
173
174 def SetDocumentSaved(self, saved=True):
175 """
176 Sets whether the document has been saved. This method has been
177 added to wxPython and is not in wxWindows.
178 """
179 self._savedYet = saved
180
181
182 def GetCommandProcessor(self):
183 """
184 Returns the command processor associated with this document.
185 """
186 return self._commandProcessor
187
188
189 def SetCommandProcessor(self, processor):
190 """
191 Sets the command processor to be used for this document. The document
192 will then be responsible for its deletion. Normally you should not
193 call this; override OnCreateCommandProcessor instead.
194 """
195 self._commandProcessor = processor
196
197
198 def IsModified(self):
199 """
200 Returns true if the document has been modified since the last save,
201 false otherwise. You may need to override this if your document view
202 maintains its own record of being modified (for example if using
203 wxTextWindow to view and edit the document).
204 """
205 return self._documentModified
206
207
208 def Modify(self, modify):
209 """
210 Call with true to mark the document as modified since the last save,
211 false otherwise. You may need to override this if your document view
212 maintains its own record of being modified (for example if using
213 xTextWindow to view and edit the document).
214 """
215 self._documentModified = modify
216
217
218 def SetDocumentModificationDate(self):
219 """
220 Saves the file's last modification date.
221 This is used to check if the file has been modified outside of the application.
222 This method has been added to wxPython and is not in wxWindows.
223 """
224 self._documentModificationDate = os.path.getmtime(self.GetFilename())
225
226
227 def GetDocumentModificationDate(self):
228 """
229 Returns the file's modification date when it was loaded from disk.
230 This is used to check if the file has been modified outside of the application.
231 This method has been added to wxPython and is not in wxWindows.
232 """
233 return self._documentModificationDate
234
235
236 def GetViews(self):
237 """
238 Returns the list whose elements are the views on the document.
239 """
240 return self._documentViews
241
242
243 def GetDocumentTemplate(self):
244 """
245 Returns the template that created the document.
246 """
247 return self._documentTemplate
248
249
250 def SetDocumentTemplate(self, template):
251 """
252 Sets the template that created the document. Should only be called by
253 the framework.
254 """
255 self._documentTemplate = template
256
257
258 def DeleteContents(self):
259 """
260 Deletes the contents of the document. Override this method as
261 necessary.
262 """
263 return True
264
265
266 def Destroy(self):
267 """
268 Destructor. Removes itself from the document manager.
269 """
270 self.DeleteContents()
271 if self.GetDocumentManager():
272 self.GetDocumentManager().RemoveDocument(self)
273 wx.EvtHandler.Destroy(self)
274
275
276 def Close(self):
277 """
278 Closes the document, by calling OnSaveModified and then (if this true)
279 OnCloseDocument. This does not normally delete the document object:
280 use DeleteAllViews to do this implicitly.
281 """
282 if self.OnSaveModified():
283 if self.OnCloseDocument():
284 return True
285 else:
286 return False
287 else:
288 return False
289
290
291 def OnCloseDocument(self):
292 """
293 The default implementation calls DeleteContents (an empty
294 implementation) sets the modified flag to false. Override this to
295 supply additional behaviour when the document is closed with Close.
296 """
297 self.NotifyClosing()
298 self.DeleteContents()
299 self.Modify(False)
300 return True
301
302
303 def DeleteAllViews(self):
304 """
305 Calls wxView.Close and deletes each view. Deleting the final view will
306 implicitly delete the document itself, because the wxView destructor
307 calls RemoveView. This in turns calls wxDocument::OnChangedViewList,
308 whose default implemention is to save and delete the document if no
309 views exist.
310 """
311 manager = self.GetDocumentManager()
312 for view in self._documentViews:
313 if not view.Close():
314 return False
315 if self in manager.GetDocuments():
316 self.Destroy()
317 return True
318
319
320 def GetFirstView(self):
321 """
322 A convenience function to get the first view for a document, because
323 in many cases a document will only have a single view.
324 """
325 if len(self._documentViews) == 0:
326 return None
327 return self._documentViews[0]
328
329
330 def GetDocumentManager(self):
331 """
332 Returns the associated document manager.
333 """
334 if self._documentTemplate:
335 return self._documentTemplate.GetDocumentManager()
336 return None
337
338
339 def OnNewDocument(self):
340 """
341 The default implementation calls OnSaveModified and DeleteContents,
342 makes a default title for the document, and notifies the views that
343 the filename (in fact, the title) has changed.
344 """
345 if not self.OnSaveModified() or not self.OnCloseDocument():
346 return False
347 self.DeleteContents()
348 self.Modify(False)
349 self.SetDocumentSaved(False)
350 name = self.GetDocumentManager().MakeDefaultName()
351 self.SetTitle(name)
352 self.SetFilename(name, notifyViews = True)
353
354
355 def Save(self):
356 """
357 Saves the document by calling OnSaveDocument if there is an associated
358 filename, or SaveAs if there is no filename.
359 """
360 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?
361 return True
362
363 """ check for file modification outside of application """
364 if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate():
365 msgTitle = wx.GetApp().GetAppName()
366 if not msgTitle:
367 msgTitle = _("Application")
368 res = wx.MessageBox(_("'%s' has been modified outside of %s. Overwrite '%s' with current changes?") % (self.GetPrintableName(), msgTitle, self.GetPrintableName()),
369 msgTitle,
370 wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION,
371 self.GetDocumentWindow())
372
373 if res == wx.NO:
374 return True
375 elif res == wx.YES:
376 pass
377 else: # elif res == wx.CANCEL:
378 return False
379
380 if not self._documentFile or not self._savedYet:
381 return self.SaveAs()
382 return self.OnSaveDocument(self._documentFile)
383
384
385 def SaveAs(self):
386 """
387 Prompts the user for a file to save to, and then calls OnSaveDocument.
388 """
389 docTemplate = self.GetDocumentTemplate()
390 if not docTemplate:
391 return False
392
393 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
394 filename = wx.FileSelector(_("Save As"),
395 docTemplate.GetDirectory(),
396 FileNameFromPath(self.GetFilename()),
397 docTemplate.GetDefaultExtension(),
398 wildcard = descr,
399 flags = wx.SAVE | wx.OVERWRITE_PROMPT,
400 parent = self.GetDocumentWindow())
401 if filename == "":
402 return False
403
404 name, ext = os.path.splitext(filename)
405 if ext == "":
406 filename += '.' + docTemplate.GetDefaultExtension()
407
408 self.SetFilename(filename)
409 self.SetTitle(FileNameFromPath(filename))
410
411 for view in self._documentViews:
412 view.OnChangeFilename()
413
414 if not self.OnSaveDocument(filename):
415 return False
416
417 if docTemplate.FileMatchesTemplate(filename):
418 self.GetDocumentManager().AddFileToHistory(filename)
419
420 return True
421
422
423 def OnSaveDocument(self, filename):
424 """
425 Constructs an output file for the given filename (which must
426 not be empty), and calls SaveObject. If SaveObject returns true, the
427 document is set to unmodified; otherwise, an error message box is
428 displayed.
429 """
430 if not filename:
431 return False
432
433 msgTitle = wx.GetApp().GetAppName()
434 if not msgTitle:
435 msgTitle = _("File Error")
436
437 backupFilename = None
438 try:
439 # if current file exists, move it to a safe place temporarily
440 if os.path.exists(filename):
441
442 # Check if read-only.
443 if not os.access(filename, os.W_OK):
444 wx.MessageBox("Could not save '%s'. No write permission to overwrite existing file." % FileNameFromPath(filename),
445 msgTitle,
446 wx.OK | wx.ICON_EXCLAMATION,
447 self.GetDocumentWindow())
448 return False
449
450 i = 1
451 backupFilename = "%s.bak%s" % (filename, i)
452 while os.path.exists(backupFilename):
453 i += 1
454 backupFilename = "%s.bak%s" % (filename, i)
455 os.rename(filename, backupFilename)
456
457 fileObject = file(filename, 'w')
458 self.SaveObject(fileObject)
459 fileObject.close()
460
461 if backupFilename:
462 os.remove(backupFilename)
463 except:
464 # save failed, restore old file
465 if backupFilename:
466 os.remove(filename)
467 os.rename(backupFilename, filename)
468 self.SetDocumentModificationDate()
469
470 wx.MessageBox("Could not save '%s'. %s" % (FileNameFromPath(filename), sys.exc_value),
471 msgTitle,
472 wx.OK | wx.ICON_EXCLAMATION,
473 self.GetDocumentWindow())
474 return False
475
476 self.SetFilename(filename, True)
477 self.Modify(False)
478 self.SetDocumentModificationDate()
479 self.SetDocumentSaved(True)
480 #if wx.Platform == '__WXMAC__': # Not yet implemented in wxPython
481 # wx.FileName(file).MacSetDefaultTypeAndCreator()
482 return True
483
484
485 def OnOpenDocument(self, filename):
486 """
487 Constructs an input file for the given filename (which must not
488 be empty), and calls LoadObject. If LoadObject returns true, the
489 document is set to unmodified; otherwise, an error message box is
490 displayed. The document's views are notified that the filename has
491 changed, to give windows an opportunity to update their titles. All of
492 the document's views are then updated.
493 """
494 if not self.OnSaveModified():
495 return False
496
497 msgTitle = wx.GetApp().GetAppName()
498 if not msgTitle:
499 msgTitle = _("File Error")
500
501 fileObject = file(filename, 'r')
502 try:
503 self.LoadObject(fileObject)
504 except:
505 wx.MessageBox("Could not open '%s'. %s" % (FileNameFromPath(filename), sys.exc_value),
506 msgTitle,
507 wx.OK | wx.ICON_EXCLAMATION,
508 self.GetDocumentWindow())
509 return False
510
511 self.SetFilename(filename, True)
512 self.Modify(False)
513 self.SetDocumentModificationDate()
514 self.SetDocumentSaved(True)
515 self.UpdateAllViews()
516 return True
517
518
519 def LoadObject(self, file):
520 """
521 Override this function and call it from your own LoadObject before
522 loading your own data. LoadObject is called by the framework
523 automatically when the document contents need to be loaded.
524
525 Note that the wxPython version simply sends you a Python file object,
526 so you can use pickle.
527 """
528 return True
529
530
531 def SaveObject(self, file):
532 """
533 Override this function and call it from your own SaveObject before
534 saving your own data. SaveObject is called by the framework
535 automatically when the document contents need to be saved.
536
537 Note that the wxPython version simply sends you a Python file object,
538 so you can use pickle.
539 """
540 return True
541
542
543 def Revert(self):
544 """
545 Override this function to revert the document to its last saved state.
546 """
547 return False
548
549
550 def GetPrintableName(self):
551 """
552 Copies a suitable document name into the supplied name buffer.
553 The default function uses the title, or if there is no title, uses the
554 filename; or if no filename, the string 'Untitled'.
555 """
556 if self._documentTitle:
557 return self._documentTitle
558 elif self._documentFile:
559 return FileNameFromPath(self._documentFile)
560 else:
561 return _("Untitled")
562
563
564 def GetDocumentWindow(self):
565 """
566 Intended to return a suitable window for using as a parent for
567 document-related dialog boxes. By default, uses the frame associated
568 with the first view.
569 """
570 if len(self._documentViews) > 0:
571 return self._documentViews[0].GetFrame()
572 else:
573 return wx.GetApp().GetTopWindow()
574
575
576 def OnCreateCommandProcessor(self):
577 """
578 Override this function if you want a different (or no) command
579 processor to be created when the document is created. By default, it
580 returns an instance of wxCommandProcessor.
581 """
582 return CommandProcessor()
583
584
585 def OnSaveModified(self):
586 """
587 If the document has been modified, prompts the user to ask if the
588 changes should be changed. If the user replies Yes, the Save function
589 is called. If No, the document is marked as unmodified and the
590 function succeeds. If Cancel, the function fails.
591 """
592 if not self.IsModified():
593 return True
594
595 """ check for file modification outside of application """
596 if os.path.exists(self.GetFilename()) and os.path.getmtime(self.GetFilename()) != self.GetDocumentModificationDate():
597 msgTitle = wx.GetApp().GetAppName()
598 if not msgTitle:
599 msgTitle = _("Warning")
600 res = wx.MessageBox(_("'%s' has been modified outside of %s. Overwrite '%s' with current changes?") % (self.GetPrintableName(), msgTitle, self.GetPrintableName()),
601 msgTitle,
602 wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION,
603 self.GetDocumentWindow())
604
605 if res == wx.NO:
606 self.Modify(False)
607 return True
608 elif res == wx.YES:
609 return wx.lib.docview.Document.Save(self)
610 else: # elif res == wx.CANCEL:
611 return False
612
613 msgTitle = wx.GetApp().GetAppName()
614 if not msgTitle:
615 msgTitle = _("Warning")
616
617 res = wx.MessageBox(_("Save changes to '%s'?") % self.GetPrintableName(),
618 msgTitle,
619 wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION,
620 self.GetDocumentWindow())
621
622 if res == wx.NO:
623 self.Modify(False)
624 return True
625 elif res == wx.YES:
626 return self.Save()
627 else: # elif res == wx.CANCEL:
628 return False
629
630
631 def Draw(context):
632 """
633 Called by printing framework to draw the view.
634 """
635 return True
636
637
638 def AddView(self, view):
639 """
640 If the view is not already in the list of views, adds the view and
641 calls OnChangedViewList.
642 """
643 if not view in self._documentViews:
644 self._documentViews.append(view)
645 self.OnChangedViewList()
646 return True
647
648
649 def RemoveView(self, view):
650 """
651 Removes the view from the document's list of views, and calls
652 OnChangedViewList.
653 """
654 if view in self._documentViews:
655 self._documentViews.remove(view)
656 self.OnChangedViewList()
657 return True
658
659
660 def OnCreate(self, path, flags):
661 """
662 The default implementation calls DeleteContents (an empty
663 implementation) sets the modified flag to false. Override this to
664 supply additional behaviour when the document is closed with Close.
665 """
666 return self.GetDocumentTemplate().CreateView(self, flags)
667
668
669 def OnChangedViewList(self):
670 """
671 Called when a view is added to or deleted from this document. The
672 default implementation saves and deletes the document if no views
673 exist (the last one has just been removed).
674 """
675 if len(self._documentViews) == 0:
676 if self.OnSaveModified():
677 pass # C version does a delete but Python will garbage collect
678
679
680 def UpdateAllViews(self, sender = None, hint = None):
681 """
682 Updates all views. If sender is non-NULL, does not update this view.
683 hint represents optional information to allow a view to optimize its
684 update.
685 """
686 for view in self._documentViews:
687 if view != sender:
688 view.OnUpdate(sender, hint)
689
690
691 def NotifyClosing(self):
692 """
693 Notifies the views that the document is going to close.
694 """
695 for view in self._documentViews:
696 view.OnClosingDocument()
697
698
699 def SetFilename(self, filename, notifyViews = False):
700 """
701 Sets the filename for this document. Usually called by the framework.
702 If notifyViews is true, wxView.OnChangeFilename is called for all
703 views.
704 """
705 self._documentFile = filename
706 if notifyViews:
707 for view in self._documentViews:
708 view.OnChangeFilename()
709
710
711 def GetWriteable(self):
712 """
713 Returns true if the document can be written to its accociated file path.
714 This method has been added to wxPython and is not in wxWindows.
715 """
716 if not self._writeable:
717 return False
718 if not self._documentFile: # Doesn't exist, do a save as
719 return True
720 else:
721 return os.access(self._documentFile, os.W_OK)
722
723
724 def SetWriteable(self, writeable):
725 """
726 Set to False if the document can not be saved. This will disable the ID_SAVE_AS
727 event and is useful for custom documents that should not be saveable. The ID_SAVE
728 event can be disabled by never Modifying the document. This method has been added
729 to wxPython and is not in wxWindows.
730 """
731 self._writeable = writeable
732
733
734 class View(wx.EvtHandler):
735 """
736 The view class can be used to model the viewing and editing component of
737 an application's file-based data. It is part of the document/view
738 framework supported by wxWindows, and cooperates with the wxDocument,
739 wxDocTemplate and wxDocManager classes.
740 """
741
742 def __init__(self):
743 """
744 Constructor. Define your own default constructor to initialize
745 application-specific data.
746 """
747 wx.EvtHandler.__init__(self)
748 self._viewDocument = None
749 self._viewFrame = None
750
751
752 def Destroy(self):
753 """
754 Destructor. Removes itself from the document's list of views.
755 """
756 if self._viewDocument:
757 self._viewDocument.RemoveView(self)
758 wx.EvtHandler.Destroy(self)
759
760
761 def ProcessEvent(self, event):
762 """
763 Processes an event, searching event tables and calling zero or more
764 suitable event handler function(s). Note that the ProcessEvent
765 method is called from the wxPython docview framework directly since
766 wxPython does not have a virtual ProcessEvent function.
767 """
768 if not self.GetDocument() or not self.GetDocument().ProcessEvent(event):
769 return False
770 else:
771 return True
772
773
774 def ProcessUpdateUIEvent(self, event):
775 """
776 Processes a UI event, searching event tables and calling zero or more
777 suitable event handler function(s). Note that the ProcessEvent
778 method is called from the wxPython docview framework directly since
779 wxPython does not have a virtual ProcessEvent function.
780 """
781 return False
782
783
784 def OnActivateView(self, activate, activeView, deactiveView):
785 """
786 Called when a view is activated by means of wxView::Activate. The
787 default implementation does nothing.
788 """
789 pass
790
791
792 def OnClosingDocument(self):
793 """
794 Override this to clean up the view when the document is being closed.
795 The default implementation does nothing.
796 """
797 pass
798
799
800 def OnDraw(self, dc):
801 """
802 Override this to draw the view for the printing framework. The
803 default implementation does nothing.
804 """
805 pass
806
807
808 def OnPrint(self, dc, info):
809 """
810 Override this to print the view for the printing framework. The
811 default implementation calls View.OnDraw.
812 """
813 self.OnDraw(dc)
814
815
816 def OnUpdate(self, sender, hint):
817 """
818 Called when the view should be updated. sender is a pointer to the
819 view that sent the update request, or NULL if no single view requested
820 the update (for instance, when the document is opened). hint is as yet
821 unused but may in future contain application-specific information for
822 making updating more efficient.
823 """
824 pass
825
826
827 def OnChangeFilename(self):
828 """
829 Called when the filename has changed. The default implementation
830 constructs a suitable title and sets the title of the view frame (if
831 any).
832 """
833 if self.GetFrame():
834 appName = wx.GetApp().GetAppName()
835 if not self.GetDocument():
836 if appName:
837 title = appName
838 else:
839 return
840 else:
841 if appName and isinstance(self.GetFrame(), DocChildFrame): # Only need app name in title for SDI
842 title = appName + _(" - ")
843 else:
844 title = ''
845 self.GetFrame().SetTitle(title + self.GetDocument().GetPrintableName())
846
847
848 def GetDocument(self):
849 """
850 Returns the document associated with the view.
851 """
852 return self._viewDocument
853
854
855 def SetDocument(self, doc):
856 """
857 Associates the given document with the view. Normally called by the
858 framework.
859 """
860 self._viewDocument = doc
861 if doc:
862 doc.AddView(self)
863
864
865 def GetViewName(self):
866 """
867 Gets the name associated with the view (passed to the wxDocTemplate
868 constructor). Not currently used by the framework.
869 """
870 return self._viewTypeName
871
872
873 def SetViewName(self, name):
874 """
875 Sets the view type name. Should only be called by the framework.
876 """
877 self._viewTypeName = name
878
879
880 def Close(self, deleteWindow=True):
881 """
882 Closes the view by calling OnClose. If deleteWindow is true, this
883 function should delete the window associated with the view.
884 """
885 if self.OnClose(deleteWindow = deleteWindow):
886 return True
887 else:
888 return False
889
890
891 def Activate(self, activate=True):
892 """
893 Call this from your view frame's OnActivate member to tell the
894 framework which view is currently active. If your windowing system
895 doesn't call OnActivate, you may need to call this function from
896 OnMenuCommand or any place where you know the view must be active, and
897 the framework will need to get the current view.
898
899 The prepackaged view frame wxDocChildFrame calls wxView.Activate from
900 its OnActivate member and from its OnMenuCommand member.
901 """
902 if self.GetDocument() and self.GetDocumentManager():
903 self.OnActivateView(activate, self, self.GetDocumentManager().GetCurrentView())
904 self.GetDocumentManager().ActivateView(self, activate)
905
906
907 def OnClose(self, deleteWindow=True):
908 """
909 Implements closing behaviour. The default implementation calls
910 wxDocument.Close to close the associated document. Does not delete the
911 view. The application may wish to do some cleaning up operations in
912 this function, if a call to wxDocument::Close succeeded. For example,
913 if your application's all share the same window, you need to
914 disassociate the window from the view and perhaps clear the window. If
915 deleteWindow is true, delete the frame associated with the view.
916 """
917 if self.GetDocument():
918 return self.GetDocument().Close()
919 else:
920 return True
921
922
923 def OnCreate(self, doc, flags):
924 """
925 wxDocManager or wxDocument creates a wxView via a wxDocTemplate. Just
926 after the wxDocTemplate creates the wxView, it calls wxView::OnCreate.
927 In its OnCreate member function, the wxView can create a
928 wxDocChildFrame or a derived class. This wxDocChildFrame provides user
929 interface elements to view and/or edit the contents of the wxDocument.
930
931 By default, simply returns true. If the function returns false, the
932 view will be deleted.
933 """
934 return True
935
936
937 def OnCreatePrintout(self):
938 """
939 Returns a wxPrintout object for the purposes of printing. It should
940 create a new object every time it is called; the framework will delete
941 objects it creates.
942
943 By default, this function returns an instance of wxDocPrintout, which
944 prints and previews one page by calling wxView.OnDraw.
945
946 Override to return an instance of a class other than wxDocPrintout.
947 """
948 return DocPrintout(self)
949
950
951 def GetFrame(self):
952 """
953 Gets the frame associated with the view (if any). Note that this
954 "frame" is not a wxFrame at all in the generic MDI implementation
955 which uses the notebook pages instead of the frames and this is why
956 this method returns a wxWindow and not a wxFrame.
957 """
958 return self._viewFrame
959
960
961 def SetFrame(self, frame):
962 """
963 Sets the frame associated with this view. The application should call
964 this if possible, to tell the view about the frame. See GetFrame for
965 the explanation about the mismatch between the "Frame" in the method
966 name and the type of its parameter.
967 """
968 self._viewFrame = frame
969
970
971 def GetDocumentManager(self):
972 """
973 Returns the document manager instance associated with this view.
974 """
975 if self._viewDocument:
976 return self.GetDocument().GetDocumentManager()
977 else:
978 return None
979
980
981 class DocTemplate(wx.Object):
982 """
983 The wxDocTemplate class is used to model the relationship between a
984 document class and a view class.
985 """
986
987
988 def __init__(self, manager, description, filter, dir, ext, docTypeName, viewTypeName, docType, viewType, flags=DEFAULT_TEMPLATE_FLAGS, icon=None):
989 """
990 Constructor. Create instances dynamically near the start of your
991 application after creating a wxDocManager instance, and before doing
992 any document or view operations.
993
994 manager is the document manager object which manages this template.
995
996 description is a short description of what the template is for. This
997 string will be displayed in the file filter list of Windows file
998 selectors.
999
1000 filter is an appropriate file filter such as *.txt.
1001
1002 dir is the default directory to use for file selectors.
1003
1004 ext is the default file extension (such as txt).
1005
1006 docTypeName is a name that should be unique for a given type of
1007 document, used for gathering a list of views relevant to a
1008 particular document.
1009
1010 viewTypeName is a name that should be unique for a given view.
1011
1012 docClass is a Python class. If this is not supplied, you will need to
1013 derive a new wxDocTemplate class and override the CreateDocument
1014 member to return a new document instance on demand.
1015
1016 viewClass is a Python class. If this is not supplied, you will need to
1017 derive a new wxDocTemplate class and override the CreateView member to
1018 return a new view instance on demand.
1019
1020 flags is a bit list of the following:
1021 wx.TEMPLATE_VISIBLE The template may be displayed to the user in
1022 dialogs.
1023
1024 wx.TEMPLATE_INVISIBLE The template may not be displayed to the user in
1025 dialogs.
1026
1027 wx.DEFAULT_TEMPLATE_FLAGS Defined as wxTEMPLATE_VISIBLE.
1028 """
1029 self._docManager = manager
1030 self._description = description
1031 self._fileFilter = filter
1032 self._directory = dir
1033 self._defaultExt = ext
1034 self._docTypeName = docTypeName
1035 self._viewTypeName = viewTypeName
1036 self._docType = docType
1037 self._viewType = viewType
1038 self._flags = flags
1039 self._icon = icon
1040
1041 self._docManager.AssociateTemplate(self)
1042
1043
1044 def GetDefaultExtension(self):
1045 """
1046 Returns the default file extension for the document data, as passed to
1047 the document template constructor.
1048 """
1049 return self._defaultExt
1050
1051
1052 def SetDefaultExtension(self, defaultExt):
1053 """
1054 Sets the default file extension.
1055 """
1056 self._defaultExt = defaultExt
1057
1058
1059 def GetDescription(self):
1060 """
1061 Returns the text description of this template, as passed to the
1062 document template constructor.
1063 """
1064 return self._description
1065
1066
1067 def SetDescription(self, description):
1068 """
1069 Sets the template description.
1070 """
1071 self._description = description
1072
1073
1074 def GetDirectory(self):
1075 """
1076 Returns the default directory, as passed to the document template
1077 constructor.
1078 """
1079 return self._directory
1080
1081
1082 def SetDirectory(self, dir):
1083 """
1084 Sets the default directory.
1085 """
1086 self._directory = dir
1087
1088
1089 def GetDocumentManager(self):
1090 """
1091 Returns the document manager instance for which this template was
1092 created.
1093 """
1094 return self._docManager
1095
1096
1097 def SetDocumentManager(self, manager):
1098 """
1099 Sets the document manager instance for which this template was
1100 created. Should not be called by the application.
1101 """
1102 self._docManager = manager
1103
1104
1105 def GetFileFilter(self):
1106 """
1107 Returns the file filter, as passed to the document template
1108 constructor.
1109 """
1110 return self._fileFilter
1111
1112
1113 def SetFileFilter(self, filter):
1114 """
1115 Sets the file filter.
1116 """
1117 self._fileFilter = filter
1118
1119
1120 def GetFlags(self):
1121 """
1122 Returns the flags, as passed to the document template constructor.
1123 (see the constructor description for more details).
1124 """
1125 return self._flags
1126
1127
1128 def SetFlags(self, flags):
1129 """
1130 Sets the internal document template flags (see the constructor
1131 description for more details).
1132 """
1133 self._flags = flags
1134
1135
1136 def GetIcon(self):
1137 """
1138 Returns the icon, as passed to the document template
1139 constructor. This method has been added to wxPython and is
1140 not in wxWindows.
1141 """
1142 return self._icon
1143
1144
1145 def SetIcon(self, flags):
1146 """
1147 Sets the icon. This method has been added to wxPython and is not
1148 in wxWindows.
1149 """
1150 self._icon = icon
1151
1152
1153 def GetDocumentType(self):
1154 """
1155 Returns the Python document class, as passed to the document template
1156 constructor.
1157 """
1158 return self._docType
1159
1160
1161 def GetViewType(self):
1162 """
1163 Returns the Python view class, as passed to the document template
1164 constructor.
1165 """
1166 return self._viewType
1167
1168
1169 def IsVisible(self):
1170 """
1171 Returns true if the document template can be shown in user dialogs,
1172 false otherwise.
1173 """
1174 return (self._flags & TEMPLATE_VISIBLE) == TEMPLATE_VISIBLE
1175
1176
1177 def GetDocumentName(self):
1178 """
1179 Returns the document type name, as passed to the document template
1180 constructor.
1181 """
1182 return self._docTypeName
1183
1184
1185 def GetViewName(self):
1186 """
1187 Returns the view type name, as passed to the document template
1188 constructor.
1189 """
1190 return self._viewTypeName
1191
1192
1193 def CreateDocument(self, path, flags):
1194 """
1195 Creates a new instance of the associated document class. If you have
1196 not supplied a class to the template constructor, you will need to
1197 override this function to return an appropriate document instance.
1198 """
1199 doc = self._docType()
1200 doc.SetFilename(path)
1201 doc.SetDocumentTemplate(self)
1202 self.GetDocumentManager().AddDocument(doc)
1203 doc.SetCommandProcessor(doc.OnCreateCommandProcessor())
1204 if doc.OnCreate(path, flags):
1205 return doc
1206 else:
1207 if doc in self.GetDocumentManager().GetDocuments():
1208 doc.DeleteAllViews()
1209 return None
1210
1211
1212 def CreateView(self, doc, flags):
1213 """
1214 Creates a new instance of the associated document view. If you have
1215 not supplied a class to the template constructor, you will need to
1216 override this function to return an appropriate view instance.
1217 """
1218 view = self._viewType()
1219 view.SetDocument(doc)
1220 if view.OnCreate(doc, flags):
1221 return view
1222 else:
1223 view.Destroy()
1224 return None
1225
1226
1227 def FileMatchesTemplate(self, path):
1228 """
1229 Returns True if the path's extension matches one of this template's
1230 file filter extensions.
1231 """
1232 ext = FindExtension(path)
1233 if not ext: return False
1234 return ext in self.GetFileFilter()
1235 # return self.GetDefaultExtension() == FindExtension(path)
1236
1237
1238 class DocManager(wx.EvtHandler):
1239 """
1240 The wxDocManager class is part of the document/view framework supported by
1241 wxWindows, and cooperates with the wxView, wxDocument and wxDocTemplate
1242 classes.
1243 """
1244
1245 def __init__(self, flags=DEFAULT_DOCMAN_FLAGS, initialize=True):
1246 """
1247 Constructor. Create a document manager instance dynamically near the
1248 start of your application before doing any document or view operations.
1249
1250 flags is used in the Python version to indicate whether the document
1251 manager is in DOC_SDI or DOC_MDI mode.
1252
1253 If initialize is true, the Initialize function will be called to
1254 create a default history list object. If you derive from wxDocManager,
1255 you may wish to call the base constructor with false, and then call
1256 Initialize in your own constructor, to allow your own Initialize or
1257 OnCreateFileHistory functions to be called.
1258 """
1259
1260 wx.EvtHandler.__init__(self)
1261
1262 self._defaultDocumentNameCounter = 1
1263 self._flags = flags
1264 self._currentView = None
1265 self._lastActiveView = None
1266 self._maxDocsOpen = 10000
1267 self._fileHistory = None
1268 self._templates = []
1269 self._docs = []
1270 self._lastDirectory = ""
1271
1272 if initialize:
1273 self.Initialize()
1274
1275 wx.EVT_MENU(self, wx.ID_OPEN, self.OnFileOpen)
1276 wx.EVT_MENU(self, wx.ID_CLOSE, self.OnFileClose)
1277 wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.OnFileCloseAll)
1278 wx.EVT_MENU(self, wx.ID_REVERT, self.OnFileRevert)
1279 wx.EVT_MENU(self, wx.ID_NEW, self.OnFileNew)
1280 wx.EVT_MENU(self, wx.ID_SAVE, self.OnFileSave)
1281 wx.EVT_MENU(self, wx.ID_SAVEAS, self.OnFileSaveAs)
1282 wx.EVT_MENU(self, wx.ID_UNDO, self.OnUndo)
1283 wx.EVT_MENU(self, wx.ID_REDO, self.OnRedo)
1284 wx.EVT_MENU(self, wx.ID_PRINT, self.OnPrint)
1285 wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.OnPrintSetup)
1286 wx.EVT_MENU(self, wx.ID_PREVIEW, self.OnPreview)
1287
1288 wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.OnUpdateFileOpen)
1289 wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.OnUpdateFileClose)
1290 wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.OnUpdateFileCloseAll)
1291 wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.OnUpdateFileRevert)
1292 wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.OnUpdateFileNew)
1293 wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.OnUpdateFileSave)
1294 wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.OnUpdateFileSaveAs)
1295 wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.OnUpdateUndo)
1296 wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.OnUpdateRedo)
1297 wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.OnUpdatePrint)
1298 wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.OnUpdatePrintSetup)
1299 wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.OnUpdatePreview)
1300
1301
1302 def Destroy(self):
1303 """
1304 Destructor.
1305 """
1306 self.Clear()
1307 wx.EvtHandler.Destroy(self)
1308
1309
1310 def GetFlags(self):
1311 """
1312 Returns the document manager's flags. This method has been
1313 added to wxPython and is not in wxWindows.
1314 """
1315 return self._flags
1316
1317
1318 def CloseDocument(self, doc, force=True):
1319 """
1320 Closes the specified document.
1321 """
1322 if doc.Close() or force:
1323 doc.DeleteAllViews()
1324 if doc in self._docs:
1325 doc.Destroy()
1326 return True
1327 return False
1328
1329
1330 def CloseDocuments(self, force=True):
1331 """
1332 Closes all currently opened documents.
1333 """
1334 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
1335 if not self.CloseDocument(document, force):
1336 return False
1337 document.DeleteAllViews() # Implicitly delete the document when the last view is removed
1338 return True
1339
1340
1341 def Clear(self, force=True):
1342 """
1343 Closes all currently opened document by callling CloseDocuments and
1344 clears the document manager's templates.
1345 """
1346 if not self.CloseDocuments(force):
1347 return False
1348 self._templates = []
1349 return True
1350
1351
1352 def Initialize(self):
1353 """
1354 Initializes data; currently just calls OnCreateFileHistory. Some data
1355 cannot always be initialized in the constructor because the programmer
1356 must be given the opportunity to override functionality. In fact
1357 Initialize is called from the wxDocManager constructor, but this can
1358 be vetoed by passing false to the second argument, allowing the
1359 derived class's constructor to call Initialize, possibly calling a
1360 different OnCreateFileHistory from the default.
1361
1362 The bottom line: if you're not deriving from Initialize, forget it and
1363 construct wxDocManager with no arguments.
1364 """
1365 self.OnCreateFileHistory()
1366 return True
1367
1368
1369 def OnCreateFileHistory(self):
1370 """
1371 A hook to allow a derived class to create a different type of file
1372 history. Called from Initialize.
1373 """
1374 self._fileHistory = wx.FileHistory()
1375
1376
1377 def OnFileClose(self, event):
1378 """
1379 Closes and deletes the currently active document.
1380 """
1381 doc = self.GetCurrentDocument()
1382 if doc:
1383 doc.DeleteAllViews()
1384 if doc in self._docs:
1385 self._docs.remove(doc)
1386
1387
1388 def OnFileCloseAll(self, event):
1389 """
1390 Closes and deletes all the currently opened documents.
1391 """
1392 return self.CloseDocuments(force = False)
1393
1394
1395 def OnFileNew(self, event):
1396 """
1397 Creates a new document and reads in the selected file.
1398 """
1399 self.CreateDocument('', DOC_NEW)
1400
1401
1402 def OnFileOpen(self, event):
1403 """
1404 Creates a new document and reads in the selected file.
1405 """
1406 if not self.CreateDocument('', DEFAULT_DOCMAN_FLAGS):
1407 self.OnOpenFileFailure()
1408
1409
1410 def OnFileRevert(self, event):
1411 """
1412 Reverts the current document by calling wxDocument.Save for the current
1413 document.
1414 """
1415 doc = self.GetCurrentDocument()
1416 if not doc:
1417 return
1418 doc.Revert()
1419
1420
1421 def OnFileSave(self, event):
1422 """
1423 Saves the current document by calling wxDocument.Save for the current
1424 document.
1425 """
1426 doc = self.GetCurrentDocument()
1427 if not doc:
1428 return
1429 doc.Save()
1430
1431
1432 def OnFileSaveAs(self, event):
1433 """
1434 Calls wxDocument.SaveAs for the current document.
1435 """
1436 doc = self.GetCurrentDocument()
1437 if not doc:
1438 return
1439 doc.SaveAs()
1440
1441
1442 def OnPrint(self, event):
1443 """
1444 Prints the current document by calling its View's OnCreatePrintout
1445 method.
1446 """
1447 view = self.GetCurrentView()
1448 if not view:
1449 return
1450
1451 printout = view.OnCreatePrintout()
1452 if printout:
1453 pdd = wx.PrintDialogData()
1454 printer = wx.Printer(pdd)
1455 printer.Print(view.GetFrame(), printout) # , True)
1456
1457
1458 def OnPrintSetup(self, event):
1459 """
1460 Presents the print setup dialog.
1461 """
1462 view = self.GetCurrentView()
1463 if view:
1464 parentWin = view.GetFrame()
1465 else:
1466 parentWin = wx.GetApp().GetTopWindow()
1467
1468 data = wx.PrintDialogData()
1469 printDialog = wx.PrintDialog(parentWin, data)
1470 printDialog.GetPrintDialogData().SetSetupDialog(True)
1471 printDialog.ShowModal()
1472 # TODO: Confirm that we don't have to remember PrintDialogData
1473
1474
1475 def OnPreview(self, event):
1476 """
1477 Previews the current document by calling its View's OnCreatePrintout
1478 method.
1479 """
1480 view = self.GetCurrentView()
1481 if not view:
1482 return
1483
1484 printout = view.OnCreatePrintout()
1485 if printout:
1486 # Pass two printout objects: for preview, and possible printing.
1487 preview = wx.PrintPreview(printout, view.OnCreatePrintout())
1488 # 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.
1489 mimicFrame = wx.GetApp().GetTopWindow()
1490 frame = wx.PreviewFrame(preview, mimicFrame, _("Print Preview"), mimicFrame.GetPosition(), mimicFrame.GetSize())
1491 frame.SetIcon(mimicFrame.GetIcon())
1492 frame.SetTitle(mimicFrame.GetTitle() + _(" - Preview"))
1493 frame.Initialize()
1494 frame.Show(True)
1495
1496
1497 def OnUndo(self, event):
1498 """
1499 Issues an Undo command to the current document's command processor.
1500 """
1501 doc = self.GetCurrentDocument()
1502 if not doc:
1503 return
1504 if doc.GetCommandProcessor():
1505 doc.GetCommandProcessor().Undo()
1506
1507
1508 def OnRedo(self, event):
1509 """
1510 Issues a Redo command to the current document's command processor.
1511 """
1512 doc = self.GetCurrentDocument()
1513 if not doc:
1514 return
1515 if doc.GetCommandProcessor():
1516 doc.GetCommandProcessor().Redo()
1517
1518
1519 def OnUpdateFileOpen(self, event):
1520 """
1521 Updates the user interface for the File Open command.
1522 """
1523 event.Enable(True)
1524
1525
1526 def OnUpdateFileClose(self, event):
1527 """
1528 Updates the user interface for the File Close command.
1529 """
1530 event.Enable(self.GetCurrentDocument() != None)
1531
1532
1533 def OnUpdateFileCloseAll(self, event):
1534 """
1535 Updates the user interface for the File Close All command.
1536 """
1537 event.Enable(self.GetCurrentDocument() != None)
1538
1539
1540 def OnUpdateFileRevert(self, event):
1541 """
1542 Updates the user interface for the File Revert command.
1543 """
1544 event.Enable(self.GetCurrentDocument() != None)
1545
1546
1547 def OnUpdateFileNew(self, event):
1548 """
1549 Updates the user interface for the File New command.
1550 """
1551 return True
1552
1553
1554 def OnUpdateFileSave(self, event):
1555 """
1556 Updates the user interface for the File Save command.
1557 """
1558 doc = self.GetCurrentDocument()
1559 event.Enable(doc != None and doc.IsModified())
1560
1561
1562 def OnUpdateFileSaveAs(self, event):
1563 """
1564 Updates the user interface for the File Save As command.
1565 """
1566 event.Enable(self.GetCurrentDocument() != None and self.GetCurrentDocument().GetWriteable())
1567
1568
1569 def OnUpdateUndo(self, event):
1570 """
1571 Updates the user interface for the Undo command.
1572 """
1573 doc = self.GetCurrentDocument()
1574 event.Enable(doc != None and doc.GetCommandProcessor() != None and doc.GetCommandProcessor().CanUndo())
1575 if doc and doc.GetCommandProcessor():
1576 doc.GetCommandProcessor().SetMenuStrings()
1577 else:
1578 event.SetText(_("Undo") + '\t' + _('Ctrl+Z'))
1579
1580
1581 def OnUpdateRedo(self, event):
1582 """
1583 Updates the user interface for the Redo command.
1584 """
1585 doc = self.GetCurrentDocument()
1586 event.Enable(doc != None and doc.GetCommandProcessor() != None and doc.GetCommandProcessor().CanRedo())
1587 if doc and doc.GetCommandProcessor():
1588 doc.GetCommandProcessor().SetMenuStrings()
1589 else:
1590 event.SetText(_("Redo") + '\t' + _('Ctrl+Y'))
1591
1592
1593 def OnUpdatePrint(self, event):
1594 """
1595 Updates the user interface for the Print command.
1596 """
1597 event.Enable(self.GetCurrentDocument() != None)
1598
1599
1600 def OnUpdatePrintSetup(self, event):
1601 """
1602 Updates the user interface for the Print Setup command.
1603 """
1604 return True
1605
1606
1607 def OnUpdatePreview(self, event):
1608 """
1609 Updates the user interface for the Print Preview command.
1610 """
1611 event.Enable(self.GetCurrentDocument() != None)
1612
1613
1614 def GetCurrentView(self):
1615 """
1616 Returns the currently active view.
1617 """
1618 if self._currentView:
1619 return self._currentView
1620 if len(self._docs) == 1:
1621 return self._docs[0].GetFirstView()
1622 return None
1623
1624
1625 def GetLastActiveView(self):
1626 """
1627 Returns the last active view. This is used in the SDI framework where dialogs can be mistaken for a view
1628 and causes the framework to deactivete the current view. This happens when something like a custom dialog box used
1629 to operate on the current view is shown.
1630 """
1631 if len(self._docs) >= 1:
1632 return self._lastActiveView
1633 else:
1634 return None
1635
1636
1637 def ProcessEvent(self, event):
1638 """
1639 Processes an event, searching event tables and calling zero or more
1640 suitable event handler function(s). Note that the ProcessEvent
1641 method is called from the wxPython docview framework directly since
1642 wxPython does not have a virtual ProcessEvent function.
1643 """
1644 view = self.GetCurrentView()
1645 if view:
1646 if view.ProcessEvent(event):
1647 return True
1648 id = event.GetId()
1649 if id == wx.ID_OPEN:
1650 self.OnFileOpen(event)
1651 return True
1652 elif id == wx.ID_CLOSE:
1653 self.OnFileClose(event)
1654 return True
1655 elif id == wx.ID_CLOSE_ALL:
1656 self.OnFileCloseAll(event)
1657 return True
1658 elif id == wx.ID_REVERT:
1659 self.OnFileRevert(event)
1660 return True
1661 elif id == wx.ID_NEW:
1662 self.OnFileNew(event)
1663 return True
1664 elif id == wx.ID_SAVE:
1665 self.OnFileSave(event)
1666 return True
1667 elif id == wx.ID_SAVEAS:
1668 self.OnFileSaveAs(event)
1669 return True
1670 elif id == wx.ID_UNDO:
1671 self.OnUndo(event)
1672 return True
1673 elif id == wx.ID_REDO:
1674 self.OnRedo(event)
1675 return True
1676 elif id == wx.ID_PRINT:
1677 self.OnPrint(event)
1678 return True
1679 elif id == wx.ID_PRINT_SETUP:
1680 self.OnPrintSetup(event)
1681 return True
1682 elif id == wx.ID_PREVIEW:
1683 self.OnPreview(event)
1684 return True
1685 else:
1686 return False
1687
1688
1689 def ProcessUpdateUIEvent(self, event):
1690 """
1691 Processes a UI event, searching event tables and calling zero or more
1692 suitable event handler function(s). Note that the ProcessEvent
1693 method is called from the wxPython docview framework directly since
1694 wxPython does not have a virtual ProcessEvent function.
1695 """
1696 id = event.GetId()
1697 view = self.GetCurrentView()
1698 if view:
1699 if view.ProcessUpdateUIEvent(event):
1700 return True
1701 if id == wx.ID_OPEN:
1702 self.OnUpdateFileOpen(event)
1703 return True
1704 elif id == wx.ID_CLOSE:
1705 self.OnUpdateFileClose(event)
1706 return True
1707 elif id == wx.ID_CLOSE_ALL:
1708 self.OnUpdateFileCloseAll(event)
1709 return True
1710 elif id == wx.ID_REVERT:
1711 self.OnUpdateFileRevert(event)
1712 return True
1713 elif id == wx.ID_NEW:
1714 self.OnUpdateFileNew(event)
1715 return True
1716 elif id == wx.ID_SAVE:
1717 self.OnUpdateFileSave(event)
1718 return True
1719 elif id == wx.ID_SAVEAS:
1720 self.OnUpdateFileSaveAs(event)
1721 return True
1722 elif id == wx.ID_UNDO:
1723 self.OnUpdateUndo(event)
1724 return True
1725 elif id == wx.ID_REDO:
1726 self.OnUpdateRedo(event)
1727 return True
1728 elif id == wx.ID_PRINT:
1729 self.OnUpdatePrint(event)
1730 return True
1731 elif id == wx.ID_PRINT_SETUP:
1732 self.OnUpdatePrintSetup(event)
1733 return True
1734 elif id == wx.ID_PREVIEW:
1735 self.OnUpdatePreview(event)
1736 return True
1737 else:
1738 return False
1739
1740
1741 def CreateDocument(self, path, flags=0):
1742 """
1743 Creates a new document in a manner determined by the flags parameter,
1744 which can be:
1745
1746 wx.lib.docview.DOC_NEW Creates a fresh document.
1747 wx.lib.docview.DOC_SILENT Silently loads the given document file.
1748
1749 If wx.lib.docview.DOC_NEW is present, a new document will be created and returned,
1750 possibly after asking the user for a template to use if there is more
1751 than one document template. If wx.lib.docview.DOC_SILENT is present, a new document
1752 will be created and the given file loaded into it. If neither of these
1753 flags is present, the user will be presented with a file selector for
1754 the file to load, and the template to use will be determined by the
1755 extension (Windows) or by popping up a template choice list (other
1756 platforms).
1757
1758 If the maximum number of documents has been reached, this function
1759 will delete the oldest currently loaded document before creating a new
1760 one.
1761
1762 wxPython version supports the document manager's wx.lib.docview.DOC_OPEN_ONCE flag.
1763 """
1764 templates = []
1765 for temp in self._templates:
1766 if temp.IsVisible():
1767 templates.append(temp)
1768 if len(templates) == 0:
1769 return None
1770
1771 if len(self.GetDocuments()) >= self._maxDocsOpen:
1772 doc = self.GetDocuments()[0]
1773 if not self.CloseDocument(doc, False):
1774 return None
1775
1776 if flags & DOC_NEW:
1777 if len(templates) == 1:
1778 temp = templates[0]
1779 newDoc = temp.CreateDocument(path, flags)
1780 if newDoc:
1781 newDoc.SetDocumentName(temp.GetDocumentName())
1782 newDoc.SetDocumentTemplate(temp)
1783 newDoc.OnNewDocument()
1784 return newDoc
1785
1786 temp = self.SelectDocumentType(templates)
1787 if temp:
1788 newDoc = temp.CreateDocument(path, flags)
1789 if newDoc:
1790 newDoc.SetDocumentName(temp.GetDocumentName())
1791 newDoc.SetDocumentTemplate(temp)
1792 newDoc.OnNewDocument()
1793 return newDoc
1794 else:
1795 return None
1796
1797 if path and flags & DOC_SILENT:
1798 temp = self.FindTemplateForPath(path)
1799 else:
1800 temp, path = self.SelectDocumentPath(templates, path, flags)
1801
1802 # Existing document
1803 if self.GetFlags() & DOC_OPEN_ONCE:
1804 for document in self._docs:
1805 if document.GetFilename() == path:
1806 """ check for file modification outside of application """
1807 if os.path.exists(path) and os.path.getmtime(path) != document.GetDocumentModificationDate():
1808 msgTitle = wx.GetApp().GetAppName()
1809 if not msgTitle:
1810 msgTitle = _("Warning")
1811 shortName = document.GetPrintableName()
1812 res = wx.MessageBox(_("'%s' has been modified outside of %s. Reload '%s' from file system?") % (shortName, msgTitle, shortName),
1813 msgTitle,
1814 wx.YES_NO | wx.ICON_QUESTION,
1815 self.FindSuitableParent())
1816 if res == wx.YES:
1817 if not self.CloseDocument(document, False):
1818 wx.MessageBox(_("Couldn't reload '%s'. Unable to close current '%s'.") % (shortName, shortName))
1819 return None
1820 return self.CreateDocument(path, flags)
1821 elif res == wx.NO: # don't ask again
1822 document.SetDocumentModificationDate()
1823
1824 firstView = document.GetFirstView()
1825 if firstView and firstView.GetFrame():
1826 firstView.GetFrame().SetFocus() # Not in wxWindows code but useful nonetheless
1827 if hasattr(firstView.GetFrame(), "IsIconized") and firstView.GetFrame().IsIconized(): # Not in wxWindows code but useful nonetheless
1828 firstView.GetFrame().Iconize(False)
1829 return None
1830
1831 if temp:
1832 newDoc = temp.CreateDocument(path, flags)
1833 if newDoc:
1834 newDoc.SetDocumentName(temp.GetDocumentName())
1835 newDoc.SetDocumentTemplate(temp)
1836 if not newDoc.OnOpenDocument(path):
1837 newDoc.DeleteAllViews() # Implicitly deleted by DeleteAllViews
1838 newDoc.GetFirstView().GetFrame().Destroy() # DeleteAllViews doesn't get rid of the frame, so we'll explicitly destroy it.
1839 return None
1840 self.AddFileToHistory(path)
1841 return newDoc
1842
1843 return None
1844
1845
1846 def CreateView(self, document, flags=0):
1847 """
1848 Creates a new view for the given document. If more than one view is
1849 allowed for the document (by virtue of multiple templates mentioning
1850 the same document type), a choice of view is presented to the user.
1851 """
1852 templates = []
1853 for temp in self._templates:
1854 if temp.IsVisible():
1855 if temp.GetDocumentName() == doc.GetDocumentName():
1856 templates.append(temp)
1857 if len(templates) == 0:
1858 return None
1859
1860 if len(templates) == 1:
1861 temp = templates[0]
1862 view = temp.CreateView(doc, flags)
1863 if view:
1864 view.SetViewName(temp.GetViewName())
1865 return view
1866
1867 temp = SelectViewType(templates)
1868 if temp:
1869 view = temp.CreateView(doc, flags)
1870 if view:
1871 view.SetViewName(temp.GetViewName())
1872 return view
1873 else:
1874 return None
1875
1876
1877 def DeleteTemplate(self, template, flags):
1878 """
1879 Placeholder, not yet implemented in wxWindows.
1880 """
1881 pass
1882
1883
1884 def FlushDoc(self, doc):
1885 """
1886 Placeholder, not yet implemented in wxWindows.
1887 """
1888 return False
1889
1890
1891 def MatchTemplate(self, path):
1892 """
1893 Placeholder, not yet implemented in wxWindows.
1894 """
1895 return None
1896
1897
1898 def GetCurrentDocument(self):
1899 """
1900 Returns the document associated with the currently active view (if any).
1901 """
1902 view = self.GetCurrentView()
1903 if view:
1904 return view.GetDocument()
1905 else:
1906 return None
1907
1908
1909 def MakeDefaultName(self):
1910 """
1911 Returns a suitable default name. This is implemented by appending an
1912 integer counter to the string "Untitled" and incrementing the counter.
1913 """
1914 name = _("Untitled %d") % self._defaultDocumentNameCounter
1915 self._defaultDocumentNameCounter = self._defaultDocumentNameCounter + 1
1916 return name
1917
1918
1919 def MakeFrameTitle(self):
1920 """
1921 Returns a suitable title for a document frame. This is implemented by
1922 appending the document name to the application name.
1923 """
1924 appName = wx.GetApp().GetAppName()
1925 if not doc:
1926 title = appName
1927 else:
1928 docName = doc.GetPrintableName()
1929 title = docName + _(" - ") + appName
1930 return title
1931
1932
1933 def AddFileToHistory(self, fileName):
1934 """
1935 Adds a file to the file history list, if we have a pointer to an
1936 appropriate file menu.
1937 """
1938 if self._fileHistory:
1939 self._fileHistory.AddFileToHistory(fileName)
1940
1941
1942 def RemoveFileFromHistory(self, i):
1943 """
1944 Removes a file from the file history list, if we have a pointer to an
1945 appropriate file menu.
1946 """
1947 if self._fileHistory:
1948 self._fileHistory.RemoveFileFromHistory(i)
1949
1950
1951 def GetFileHistory(self):
1952 """
1953 Returns the file history.
1954 """
1955 return self._fileHistory
1956
1957
1958 def GetHistoryFile(self, i):
1959 """
1960 Returns the file at index i from the file history.
1961 """
1962 if self._fileHistory:
1963 return self._fileHistory.GetHistoryFile(i)
1964 else:
1965 return None
1966
1967
1968 def FileHistoryUseMenu(self, menu):
1969 """
1970 Use this menu for appending recently-visited document filenames, for
1971 convenient access. Calling this function with a valid menu enables the
1972 history list functionality.
1973
1974 Note that you can add multiple menus using this function, to be
1975 managed by the file history object.
1976 """
1977 if self._fileHistory:
1978 self._fileHistory.UseMenu(menu)
1979
1980
1981 def FileHistoryRemoveMenu(self, menu):
1982 """
1983 Removes the given menu from the list of menus managed by the file
1984 history object.
1985 """
1986 if self._fileHistory:
1987 self._fileHistory.RemoveMenu(menu)
1988
1989
1990 def FileHistoryLoad(self, config):
1991 """
1992 Loads the file history from a config object.
1993 """
1994 if self._fileHistory:
1995 self._fileHistory.Load(config)
1996
1997
1998 def FileHistorySave(self, config):
1999 """
2000 Saves the file history into a config object. This must be called
2001 explicitly by the application.
2002 """
2003 if self._fileHistory:
2004 self._fileHistory.Save(config)
2005
2006
2007 def FileHistoryAddFilesToMenu(self, menu=None):
2008 """
2009 Appends the files in the history list, to all menus managed by the
2010 file history object.
2011
2012 If menu is specified, appends the files in the history list to the
2013 given menu only.
2014 """
2015 if self._fileHistory:
2016 if menu:
2017 self._fileHistory.AddFilesToThisMenu(menu)
2018 else:
2019 self._fileHistory.AddFilesToMenu()
2020
2021
2022 def GetHistoryFilesCount(self):
2023 """
2024 Returns the number of files currently stored in the file history.
2025 """
2026 if self._fileHistory:
2027 return self._fileHistory.GetNoHistoryFiles()
2028 else:
2029 return 0
2030
2031
2032 def FindTemplateForPath(self, path):
2033 """
2034 Given a path, try to find template that matches the extension. This is
2035 only an approximate method of finding a template for creating a
2036 document.
2037 """
2038 for temp in self._templates:
2039 if temp.FileMatchesTemplate(path):
2040 return temp
2041 return None
2042
2043
2044 def FindSuitableParent(self):
2045 """
2046 Returns a parent frame or dialog, either the frame with the current
2047 focus or if there is no current focus the application's top frame.
2048 """
2049 parent = wx.GetApp().GetTopWindow()
2050 focusWindow = wx.Window_FindFocus()
2051 if focusWindow:
2052 while focusWindow and not isinstance(focusWindow, wx.Dialog) and not isinstance(focusWindow, wx.Frame):
2053 focusWindow = focusWindow.GetParent()
2054 if focusWindow:
2055 parent = focusWindow
2056 return parent
2057
2058
2059 def SelectDocumentPath(self, templates, flags, save):
2060 """
2061 Under Windows, pops up a file selector with a list of filters
2062 corresponding to document templates. The wxDocTemplate corresponding
2063 to the selected file's extension is returned.
2064
2065 On other platforms, if there is more than one document template a
2066 choice list is popped up, followed by a file selector.
2067
2068 This function is used in wxDocManager.CreateDocument.
2069 """
2070 if wx.Platform == "__WXMSW__" or wx.Platform == "__WXGTK__" or wx.Platform == "__WXMAC__":
2071 allfilter = ''
2072 descr = ''
2073 for temp in templates:
2074 if temp.IsVisible():
2075 if len(descr) > 0:
2076 descr = descr + _('|')
2077 allfilter = allfilter + _(';')
2078 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
2079 allfilter = allfilter + temp.GetFileFilter()
2080 descr = _("All") + _(" (") + allfilter + _(") |") + allfilter + _('|') + descr # spacing is important, make sure there is no space after the "|", it causes a bug on wx_gtk
2081 else:
2082 descr = _("*.*")
2083
2084 path = wx.FileSelector(_("Select a File"),
2085 self._lastDirectory,
2086 _(""),
2087 wildcard = descr,
2088 flags = wx.HIDE_READONLY,
2089 parent = self.FindSuitableParent())
2090 if path:
2091 if not FileExists(path):
2092 msgTitle = wx.GetApp().GetAppName()
2093 if not msgTitle:
2094 msgTitle = _("File Error")
2095 wx.MessageBox("Could not open '%s'." % FileNameFromPath(path),
2096 msgTitle,
2097 wx.OK | wx.ICON_EXCLAMATION,
2098 parent)
2099 return (None, None)
2100 self._lastDirectory = PathOnly(path)
2101
2102 theTemplate = self.FindTemplateForPath(path)
2103 return (theTemplate, path)
2104
2105 return (None, None)
2106
2107
2108 def OnOpenFileFailure(self):
2109 """
2110 Called when there is an error opening a file.
2111 """
2112 pass
2113
2114
2115 def SelectDocumentType(self, temps, sort=False):
2116 """
2117 Returns a document template by asking the user (if there is more than
2118 one template). This function is used in wxDocManager.CreateDocument.
2119
2120 Parameters
2121
2122 templates - list of templates from which to choose a desired template.
2123
2124 sort - If more than one template is passed in in templates, then this
2125 parameter indicates whether the list of templates that the user will
2126 have to choose from is sorted or not when shown the choice box dialog.
2127 Default is false.
2128 """
2129 templates = []
2130 for temp in temps:
2131 if temp.IsVisible():
2132 want = True
2133 for temp2 in templates:
2134 if temp.GetDocumentName() == temp2.GetDocumentName() and temp.GetViewName() == temp2.GetViewName():
2135 want = False
2136 break
2137 if want:
2138 templates.append(temp)
2139
2140 if len(templates) == 0:
2141 return None
2142 elif len(templates) == 1:
2143 return template[0]
2144
2145 if sort:
2146 def tempcmp(a, b):
2147 return cmp(a.GetDescription(), b.GetDescription())
2148 templates.sort(tempcmp)
2149
2150 strings = []
2151 for temp in templates:
2152 strings.append(temp.GetDescription())
2153
2154 res = wx.GetSingleChoiceIndex(_("Select a document type:"),
2155 _("Documents"),
2156 strings,
2157 self.FindSuitableParent())
2158 if res == -1:
2159 return None
2160 return templates[res]
2161
2162
2163 def SelectViewType(self, temps, sort=False):
2164 """
2165 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.
2166 """
2167 templates = []
2168 strings = []
2169 for temp in temps:
2170 if temp.IsVisible() and temp.GetViewTypeName():
2171 if temp.GetViewName() not in strings:
2172 templates.append(temp)
2173 strings.append(temp.GetViewTypeName())
2174
2175 if len(templates) == 0:
2176 return None
2177 elif len(templates) == 1:
2178 return templates[0]
2179
2180 if sort:
2181 def tempcmp(a, b):
2182 return cmp(a.GetViewTypeName(), b.GetViewTypeName())
2183 templates.sort(tempcmp)
2184
2185 res = wx.GetSingleChoiceIndex(_("Select a document view:"),
2186 _("Views"),
2187 strings,
2188 self.FindSuitableParent())
2189 if res == -1:
2190 return None
2191 return templates[res]
2192
2193
2194 def GetTemplates(self):
2195 """
2196 Returns the document manager's template list. This method has been added to
2197 wxPython and is not in wxWindows.
2198 """
2199 return self._templates
2200
2201
2202 def AssociateTemplate(self, docTemplate):
2203 """
2204 Adds the template to the document manager's template list.
2205 """
2206 if docTemplate not in self._templates:
2207 self._templates.append(docTemplate)
2208
2209
2210 def DisassociateTemplate(self, docTemplate):
2211 """
2212 Removes the template from the list of templates.
2213 """
2214 self._templates.remove(docTemplate)
2215
2216
2217 def AddDocument(self, document):
2218 """
2219 Adds the document to the list of documents.
2220 """
2221 if document not in self._docs:
2222 self._docs.append(document)
2223
2224
2225 def RemoveDocument(self, doc):
2226 """
2227 Removes the document from the list of documents.
2228 """
2229 if doc in self._docs:
2230 self._docs.remove(doc)
2231
2232
2233 def ActivateView(self, view, activate=True, deleting=False):
2234 """
2235 Sets the current view.
2236 """
2237 if activate:
2238 self._currentView = view
2239 self._lastActiveView = view
2240 else:
2241 self._currentView = None
2242
2243
2244 def GetMaxDocsOpen(self):
2245 """
2246 Returns the number of documents that can be open simultaneously.
2247 """
2248 return self._maxDocsOpen
2249
2250
2251 def SetMaxDocsOpen(self, maxDocsOpen):
2252 """
2253 Sets the maximum number of documents that can be open at a time. By
2254 default, this is 10,000. If you set it to 1, existing documents will
2255 be saved and deleted when the user tries to open or create a new one
2256 (similar to the behaviour of Windows Write, for example). Allowing
2257 multiple documents gives behaviour more akin to MS Word and other
2258 Multiple Document Interface applications.
2259 """
2260 self._maxDocsOpen = maxDocsOpen
2261
2262
2263 def GetDocuments(self):
2264 """
2265 Returns the list of documents.
2266 """
2267 return self._docs
2268
2269
2270 class DocParentFrame(wx.Frame):
2271 """
2272 The wxDocParentFrame class provides a default top-level frame for
2273 applications using the document/view framework. This class can only be
2274 used for SDI (not MDI) parent frames.
2275
2276 It cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplates
2277 classes.
2278 """
2279
2280 def __init__(self, manager, frame, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame"):
2281 """
2282 Constructor. Note that the event table must be rebuilt for the
2283 frame since the EvtHandler is not virtual.
2284 """
2285 wx.Frame.__init__(self, frame, id, title, pos, size, style)
2286 self._docManager = manager
2287
2288 wx.EVT_CLOSE(self, self.OnCloseWindow)
2289
2290 wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit)
2291 wx.EVT_MENU_RANGE(self, wx.ID_FILE1, wx.ID_FILE9, self.OnMRUFile)
2292
2293 wx.EVT_MENU(self, wx.ID_NEW, self.ProcessEvent)
2294 wx.EVT_MENU(self, wx.ID_OPEN, self.ProcessEvent)
2295 wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.ProcessEvent)
2296 wx.EVT_MENU(self, wx.ID_CLOSE, self.ProcessEvent)
2297 wx.EVT_MENU(self, wx.ID_REVERT, self.ProcessEvent)
2298 wx.EVT_MENU(self, wx.ID_SAVE, self.ProcessEvent)
2299 wx.EVT_MENU(self, wx.ID_SAVEAS, self.ProcessEvent)
2300 wx.EVT_MENU(self, wx.ID_UNDO, self.ProcessEvent)
2301 wx.EVT_MENU(self, wx.ID_REDO, self.ProcessEvent)
2302 wx.EVT_MENU(self, wx.ID_PRINT, self.ProcessEvent)
2303 wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.ProcessEvent)
2304 wx.EVT_MENU(self, wx.ID_PREVIEW, self.ProcessEvent)
2305
2306 wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.ProcessUpdateUIEvent)
2307 wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.ProcessUpdateUIEvent)
2308 wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.ProcessUpdateUIEvent)
2309 wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.ProcessUpdateUIEvent)
2310 wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.ProcessUpdateUIEvent)
2311 wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.ProcessUpdateUIEvent)
2312 wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.ProcessUpdateUIEvent)
2313 wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.ProcessUpdateUIEvent)
2314 wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.ProcessUpdateUIEvent)
2315 wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.ProcessUpdateUIEvent)
2316 wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.ProcessUpdateUIEvent)
2317 wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.ProcessUpdateUIEvent)
2318
2319
2320 def ProcessEvent(self, event):
2321 """
2322 Processes an event, searching event tables and calling zero or more
2323 suitable event handler function(s). Note that the ProcessEvent
2324 method is called from the wxPython docview framework directly since
2325 wxPython does not have a virtual ProcessEvent function.
2326 """
2327 return self._docManager and self._docManager.ProcessEvent(event)
2328
2329
2330 def ProcessUpdateUIEvent(self, event):
2331 """
2332 Processes a UI event, searching event tables and calling zero or more
2333 suitable event handler function(s). Note that the ProcessEvent
2334 method is called from the wxPython docview framework directly since
2335 wxPython does not have a virtual ProcessEvent function.
2336 """
2337 return self._docManager and self._docManager.ProcessUpdateUIEvent(event)
2338
2339
2340 def OnExit(self, event):
2341 """
2342 Called when File/Exit is chosen and closes the window.
2343 """
2344 self.Close()
2345
2346
2347 def OnMRUFile(self, event):
2348 """
2349 Opens the appropriate file when it is selected from the file history
2350 menu.
2351 """
2352 n = event.GetId() - wx.ID_FILE1
2353 filename = self._docManager.GetHistoryFile(n)
2354 if filename:
2355 self._docManager.CreateDocument(filename, DOC_SILENT)
2356 else:
2357 self._docManager.RemoveFileFromHistory(n)
2358 msgTitle = wx.GetApp().GetAppName()
2359 if not msgTitle:
2360 msgTitle = _("File Error")
2361 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),
2362 msgTitle,
2363 wx.OK | wx.ICON_EXCLAMATION,
2364 self)
2365
2366
2367 def OnCloseWindow(self, event):
2368 """
2369 Deletes all views and documents. If no user input cancelled the
2370 operation, the frame will be destroyed and the application will exit.
2371 """
2372 if self._docManager.Clear(not event.CanVeto()):
2373 self.Destroy()
2374 else:
2375 event.Veto()
2376
2377
2378 class DocChildFrame(wx.Frame):
2379 """
2380 The wxDocChildFrame class provides a default frame for displaying
2381 documents on separate windows. This class can only be used for SDI (not
2382 MDI) child frames.
2383
2384 The class is part of the document/view framework supported by wxWindows,
2385 and cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate
2386 classes.
2387 """
2388
2389
2390 def __init__(self, doc, view, frame, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame"):
2391 """
2392 Constructor. Note that the event table must be rebuilt for the
2393 frame since the EvtHandler is not virtual.
2394 """
2395 wx.Frame.__init__(self, frame, id, title, pos, size, style, name)
2396 wx.EVT_ACTIVATE(self, self.OnActivate)
2397 wx.EVT_CLOSE(self, self.OnCloseWindow)
2398 self._childDocument = doc
2399 self._childView = view
2400 if view:
2401 view.SetFrame(self)
2402
2403 wx.EVT_MENU(self, wx.ID_NEW, self.ProcessEvent)
2404 wx.EVT_MENU(self, wx.ID_OPEN, self.ProcessEvent)
2405 wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.ProcessEvent)
2406 wx.EVT_MENU(self, wx.ID_CLOSE, self.ProcessEvent)
2407 wx.EVT_MENU(self, wx.ID_REVERT, self.ProcessEvent)
2408 wx.EVT_MENU(self, wx.ID_SAVE, self.ProcessEvent)
2409 wx.EVT_MENU(self, wx.ID_SAVEAS, self.ProcessEvent)
2410 wx.EVT_MENU(self, wx.ID_UNDO, self.ProcessEvent)
2411 wx.EVT_MENU(self, wx.ID_REDO, self.ProcessEvent)
2412 wx.EVT_MENU(self, wx.ID_PRINT, self.ProcessEvent)
2413 wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.ProcessEvent)
2414 wx.EVT_MENU(self, wx.ID_PREVIEW, self.ProcessEvent)
2415
2416 wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.ProcessUpdateUIEvent)
2417 wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.ProcessUpdateUIEvent)
2418 wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.ProcessUpdateUIEvent)
2419 wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.ProcessUpdateUIEvent)
2420 wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.ProcessUpdateUIEvent)
2421 wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.ProcessUpdateUIEvent)
2422 wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.ProcessUpdateUIEvent)
2423 wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.ProcessUpdateUIEvent)
2424 wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.ProcessUpdateUIEvent)
2425 wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.ProcessUpdateUIEvent)
2426 wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.ProcessUpdateUIEvent)
2427 wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.ProcessUpdateUIEvent)
2428
2429
2430 def ProcessEvent(self, event):
2431 """
2432 Processes an event, searching event tables and calling zero or more
2433 suitable event handler function(s). Note that the ProcessEvent
2434 method is called from the wxPython docview framework directly since
2435 wxPython does not have a virtual ProcessEvent function.
2436 """
2437 if self._childView:
2438 self._childView.Activate(True)
2439 if not self._childView or not self._childView.ProcessEvent(event):
2440 # IsInstance not working, but who cares just send all the commands up since this isn't a real ProcessEvent like wxWindows
2441 # if not isinstance(event, wx.CommandEvent) or not self.GetParent() or not self.GetParent().ProcessEvent(event):
2442 if not self.GetParent() or not self.GetParent().ProcessEvent(event):
2443 return False
2444 else:
2445 return True
2446 else:
2447 return True
2448
2449
2450 def ProcessUpdateUIEvent(self, event):
2451 """
2452 Processes a UI event, searching event tables and calling zero or more
2453 suitable event handler function(s). Note that the ProcessEvent
2454 method is called from the wxPython docview framework directly since
2455 wxPython does not have a virtual ProcessEvent function.
2456 """
2457 if self.GetParent():
2458 self.GetParent().ProcessUpdateUIEvent(event)
2459 else:
2460 return False
2461
2462
2463 def OnActivate(self, event):
2464 """
2465 Activates the current view.
2466 """
2467 # wx.Frame.OnActivate(event) This is in the wxWindows docview demo but there is no such method in wxPython, so do a Raise() instead
2468 if self._childView:
2469 self._childView.Activate(event.GetActive())
2470
2471
2472 def OnCloseWindow(self, event):
2473 """
2474 Closes and deletes the current view and document.
2475 """
2476 if self._childView:
2477 ans = False
2478 if not event.CanVeto():
2479 ans = True
2480 else:
2481 ans = self._childView.Close(deleteWindow = False)
2482
2483 if ans:
2484 self._childView.Activate(False)
2485 self._childView.Destroy()
2486 self._childView = None
2487 if self._childDocument:
2488 self._childDocument.Destroy() # This isn't in the wxWindows codebase but the document needs to be disposed of somehow
2489 self._childDocument = None
2490 self.Destroy()
2491 else:
2492 event.Veto()
2493 else:
2494 event.Veto()
2495
2496
2497 def GetDocument(self):
2498 """
2499 Returns the document associated with this frame.
2500 """
2501 return self._childDocument
2502
2503
2504 def SetDocument(self, document):
2505 """
2506 Sets the document for this frame.
2507 """
2508 self._childDocument = document
2509
2510
2511 def GetView(self):
2512 """
2513 Returns the view associated with this frame.
2514 """
2515 return self._childView
2516
2517
2518 def SetView(self, view):
2519 """
2520 Sets the view for this frame.
2521 """
2522 self._childView = view
2523
2524
2525 class DocMDIParentFrame(wx.MDIParentFrame):
2526 """
2527 The wxDocMDIParentFrame class provides a default top-level frame for
2528 applications using the document/view framework. This class can only be
2529 used for MDI parent frames.
2530
2531 It cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate
2532 classes.
2533 """
2534
2535
2536 def __init__(self, manager, frame, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame"):
2537 """
2538 Constructor. Note that the event table must be rebuilt for the
2539 frame since the EvtHandler is not virtual.
2540 """
2541 wx.MDIParentFrame.__init__(self, frame, id, title, pos, size, style, name)
2542 self._docManager = manager
2543
2544 wx.EVT_CLOSE(self, self.OnCloseWindow)
2545
2546 wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit)
2547 wx.EVT_MENU_RANGE(self, wx.ID_FILE1, wx.ID_FILE9, self.OnMRUFile)
2548
2549 wx.EVT_MENU(self, wx.ID_NEW, self.ProcessEvent)
2550 wx.EVT_MENU(self, wx.ID_OPEN, self.ProcessEvent)
2551 wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.ProcessEvent)
2552 wx.EVT_MENU(self, wx.ID_CLOSE, self.ProcessEvent)
2553 wx.EVT_MENU(self, wx.ID_REVERT, self.ProcessEvent)
2554 wx.EVT_MENU(self, wx.ID_SAVE, self.ProcessEvent)
2555 wx.EVT_MENU(self, wx.ID_SAVEAS, self.ProcessEvent)
2556 wx.EVT_MENU(self, wx.ID_UNDO, self.ProcessEvent)
2557 wx.EVT_MENU(self, wx.ID_REDO, self.ProcessEvent)
2558 wx.EVT_MENU(self, wx.ID_PRINT, self.ProcessEvent)
2559 wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.ProcessEvent)
2560 wx.EVT_MENU(self, wx.ID_PREVIEW, self.ProcessEvent)
2561
2562 wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.ProcessUpdateUIEvent)
2563 wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.ProcessUpdateUIEvent)
2564 wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.ProcessUpdateUIEvent)
2565 wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.ProcessUpdateUIEvent)
2566 wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.ProcessUpdateUIEvent)
2567 wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.ProcessUpdateUIEvent)
2568 wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.ProcessUpdateUIEvent)
2569 wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.ProcessUpdateUIEvent)
2570 wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.ProcessUpdateUIEvent)
2571 wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.ProcessUpdateUIEvent)
2572 wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.ProcessUpdateUIEvent)
2573 wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.ProcessUpdateUIEvent)
2574
2575
2576 def ProcessEvent(self, event):
2577 """
2578 Processes an event, searching event tables and calling zero or more
2579 suitable event handler function(s). Note that the ProcessEvent
2580 method is called from the wxPython docview framework directly since
2581 wxPython does not have a virtual ProcessEvent function.
2582 """
2583 return self._docManager and self._docManager.ProcessEvent(event)
2584
2585
2586 def ProcessUpdateUIEvent(self, event):
2587 """
2588 Processes a UI event, searching event tables and calling zero or more
2589 suitable event handler function(s). Note that the ProcessEvent
2590 method is called from the wxPython docview framework directly since
2591 wxPython does not have a virtual ProcessEvent function.
2592 """
2593 return self._docManager and self._docManager.ProcessUpdateUIEvent(event)
2594
2595
2596 def OnExit(self, event):
2597 """
2598 Called when File/Exit is chosen and closes the window.
2599 """
2600 self.Close()
2601
2602
2603 def OnMRUFile(self, event):
2604 """
2605 Opens the appropriate file when it is selected from the file history
2606 menu.
2607 """
2608 n = event.GetId() - wx.ID_FILE1
2609 filename = self._docManager.GetHistoryFile(n)
2610 if filename:
2611 self._docManager.CreateDocument(filename, DOC_SILENT)
2612 else:
2613 self._docManager.RemoveFileFromHistory(n)
2614 msgTitle = wx.GetApp().GetAppName()
2615 if not msgTitle:
2616 msgTitle = _("File Error")
2617 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),
2618 msgTitle,
2619 wx.OK | wx.ICON_EXCLAMATION,
2620 self)
2621
2622
2623 def OnCloseWindow(self, event):
2624 """
2625 Deletes all views and documents. If no user input cancelled the
2626 operation, the frame will be destroyed and the application will exit.
2627 """
2628 if self._docManager.Clear(not event.CanVeto()):
2629 self.Destroy()
2630 else:
2631 event.Veto()
2632
2633
2634 class DocMDIChildFrame(wx.MDIChildFrame):
2635 """
2636 The wxDocMDIChildFrame class provides a default frame for displaying
2637 documents on separate windows. This class can only be used for MDI child
2638 frames.
2639
2640 The class is part of the document/view framework supported by wxWindows,
2641 and cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate
2642 classes.
2643 """
2644
2645
2646 def __init__(self, doc, view, frame, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame"):
2647 """
2648 Constructor. Note that the event table must be rebuilt for the
2649 frame since the EvtHandler is not virtual.
2650 """
2651 wx.MDIChildFrame.__init__(self, frame, id, title, pos, size, style, name)
2652 self._childDocument = doc
2653 self._childView = view
2654 if view:
2655 view.SetFrame(self)
2656 # self.Create(doc, view, frame, id, title, pos, size, style, name)
2657 self._activeEvent = None
2658 self._activated = 0
2659 wx.EVT_ACTIVATE(self, self.OnActivate)
2660 wx.EVT_CLOSE(self, self.OnCloseWindow)
2661
2662 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
2663 mdiChildren = filter(lambda x: isinstance(x, wx.MDIChildFrame), frame.GetChildren())
2664 if len(mdiChildren) == 1:
2665 self.Activate()
2666
2667
2668 ## # Couldn't get this to work, but seems to work fine with single stage construction
2669 ## def Create(self, doc, view, frame, id, title, pos, size, style, name):
2670 ## self._childDocument = doc
2671 ## self._childView = view
2672 ## if wx.MDIChildFrame.Create(self, frame, id, title, pos, size, style, name):
2673 ## if view:
2674 ## view.SetFrame(self)
2675 ## return True
2676 ## return False
2677
2678
2679
2680 def Activate(self): # Need this in case there are embedded sash windows and such, OnActivate is not getting called
2681 """
2682 Activates the current view.
2683 """
2684 if self._childView:
2685 self._childView.Activate(True)
2686
2687
2688 def ProcessEvent(event):
2689 """
2690 Processes an event, searching event tables and calling zero or more
2691 suitable event handler function(s). Note that the ProcessEvent
2692 method is called from the wxPython docview framework directly since
2693 wxPython does not have a virtual ProcessEvent function.
2694 """
2695 if self._activeEvent == event:
2696 return False
2697
2698 self._activeEvent = event # Break recursion loops
2699
2700 if self._childView:
2701 self._childView.Activate(True)
2702
2703 if not self._childView or not self._childView.ProcessEvent(event):
2704 if not isinstance(event, wx.CommandEvent) or not self.GetParent() or not self.GetParent().ProcessEvent(event):
2705 ret = False
2706 else:
2707 ret = True
2708 else:
2709 ret = True
2710
2711 self._activeEvent = None
2712 return ret
2713
2714
2715 def OnActivate(self, event):
2716 """
2717 Sets the currently active view to be the frame's view. You may need to
2718 override (but still call) this function in order to set the keyboard
2719 focus for your subwindow.
2720 """
2721 if self._activated != 0:
2722 return True
2723 self._activated += 1
2724 wx.MDIChildFrame.Activate(self)
2725 if event.GetActive() and self._childView:
2726 self._childView.Activate(event.GetActive())
2727 self._activated = 0
2728
2729 def OnCloseWindow(self, event):
2730 """
2731 Closes and deletes the current view and document.
2732 """
2733 if self._childView:
2734 ans = False
2735 if not event.CanVeto():
2736 ans = True
2737 else:
2738 ans = self._childView.Close(deleteWindow = False)
2739
2740 if ans:
2741 self._childView.Activate(False)
2742 self._childView.Destroy()
2743 self._childView = None
2744 if self._childDocument:
2745 self._childDocument.Destroy() # This isn't in the wxWindows codebase but the document needs to be disposed of somehow
2746 self._childDocument = None
2747 self.Destroy()
2748 else:
2749 event.Veto()
2750 else:
2751 event.Veto()
2752
2753
2754 def GetDocument(self):
2755 """
2756 Returns the document associated with this frame.
2757 """
2758 return self._childDocument
2759
2760
2761 def SetDocument(self, document):
2762 """
2763 Sets the document for this frame.
2764 """
2765 self._childDocument = document
2766
2767
2768 def GetView(self):
2769 """
2770 Returns the view associated with this frame.
2771 """
2772 return self._childView
2773
2774
2775 def SetView(self, view):
2776 """
2777 Sets the view for this frame.
2778 """
2779 self._childView = view
2780
2781
2782 class DocPrintout(wx.Printout):
2783 """
2784 DocPrintout is a default Printout that prints the first page of a document
2785 view.
2786 """
2787
2788
2789 def __init__(self, view, title="Printout"):
2790 """
2791 Constructor.
2792 """
2793 wx.Printout.__init__(self)
2794 self._printoutView = view
2795
2796
2797 def GetView(self):
2798 """
2799 Returns the DocPrintout's view.
2800 """
2801 return self._printoutView
2802
2803
2804 def OnPrintPage(self, page):
2805 """
2806 Prints the first page of the view.
2807 """
2808 dc = self.GetDC()
2809 ppiScreenX, ppiScreenY = self.GetPPIScreen()
2810 ppiPrinterX, ppiPrinterY = self.GetPPIPrinter()
2811 scale = ppiPrinterX/ppiScreenX
2812 w, h = dc.GetSize()
2813 pageWidth, pageHeight = self.GetPageSizePixels()
2814 overallScale = scale * w / pageWidth
2815 dc.SetUserScale(overallScale, overallScale)
2816 if self._printoutView:
2817 self._printoutView.OnDraw(dc)
2818 return True
2819
2820
2821 def HasPage(self, pageNum):
2822 """
2823 Indicates that the DocPrintout only has a single page.
2824 """
2825 return pageNum == 1
2826
2827
2828 def OnBeginDocument(self, startPage, endPage):
2829 """
2830 Not quite sure why this was overridden, but it was in wxWindows! :)
2831 """
2832 if not wx.Printout.base_OnBeginDocument(self, startPage, endPage):
2833 return False
2834 return True
2835
2836
2837 def GetPageInfo(self):
2838 """
2839 Indicates that the DocPrintout only has a single page.
2840 """
2841 minPage = 1
2842 maxPage = 1
2843 selPageFrom = 1
2844 selPageTo = 1
2845 return (minPage, maxPage, selPageFrom, selPageTo)
2846
2847
2848 #----------------------------------------------------------------------
2849 # Command Classes
2850 #----------------------------------------------------------------------
2851
2852 class Command(wx.Object):
2853 """
2854 wxCommand is a base class for modelling an application command, which is
2855 an action usually performed by selecting a menu item, pressing a toolbar
2856 button or any other means provided by the application to change the data
2857 or view.
2858 """
2859
2860
2861 def __init__(self, canUndo = False, name = None):
2862 """
2863 Constructor. wxCommand is an abstract class, so you will need to
2864 derive a new class and call this constructor from your own constructor.
2865
2866 canUndo tells the command processor whether this command is undo-able.
2867 You can achieve the same functionality by overriding the CanUndo member
2868 function (if for example the criteria for undoability is context-
2869 dependent).
2870
2871 name must be supplied for the command processor to display the command
2872 name in the application's edit menu.
2873 """
2874 self._canUndo = canUndo
2875 self._name = name
2876
2877
2878 def CanUndo(self):
2879 """
2880 Returns true if the command can be undone, false otherwise.
2881 """
2882 return self._canUndo
2883
2884
2885 def GetName(self):
2886 """
2887 Returns the command name.
2888 """
2889 return self._name
2890
2891
2892 def Do(self):
2893 """
2894 Override this member function to execute the appropriate action when
2895 called. Return true to indicate that the action has taken place, false
2896 otherwise. Returning false will indicate to the command processor that
2897 the action is not undoable and should not be added to the command
2898 history.
2899 """
2900 return True
2901
2902
2903 def Undo(self):
2904 """
2905 Override this member function to un-execute a previous Do. Return true
2906 to indicate that the action has taken place, false otherwise. Returning
2907 false will indicate to the command processor that the action is not
2908 redoable and no change should be made to the command history.
2909
2910 How you implement this command is totally application dependent, but
2911 typical strategies include:
2912
2913 Perform an inverse operation on the last modified piece of data in the
2914 document. When redone, a copy of data stored in command is pasted back
2915 or some operation reapplied. This relies on the fact that you know the
2916 ordering of Undos; the user can never Undo at an arbitrary position in
2917 he command history.
2918
2919 Restore the entire document state (perhaps using document
2920 transactioning). Potentially very inefficient, but possibly easier to
2921 code if the user interface and data are complex, and an 'inverse
2922 execute' operation is hard to write.
2923 """
2924 return True
2925
2926
2927 class CommandProcessor(wx.Object):
2928 """
2929 wxCommandProcessor is a class that maintains a history of wxCommands, with
2930 undo/redo functionality built-in. Derive a new class from this if you want
2931 different behaviour.
2932 """
2933
2934
2935 def __init__(self, maxCommands=-1):
2936 """
2937 Constructor. maxCommands may be set to a positive integer to limit
2938 the number of commands stored to it, otherwise (and by default) the
2939 list of commands can grow arbitrarily.
2940 """
2941 self._maxCommands = maxCommands
2942 self._editMenu = None
2943 self._undoAccelerator = _("Ctrl+Z")
2944 self._redoAccelerator = _("Ctrl+Y")
2945 self.ClearCommands()
2946
2947
2948 def _GetCurrentCommand(self):
2949 if len(self._commands) == 0:
2950 return None
2951 else:
2952 return self._commands[-1]
2953
2954
2955 def _GetCurrentRedoCommand(self):
2956 if len(self._redoCommands) == 0:
2957 return None
2958 else:
2959 return self._redoCommands[-1]
2960
2961
2962 def GetMaxCommands(self):
2963 """
2964 Returns the maximum number of commands that the command processor
2965 stores.
2966
2967 """
2968 return self._maxCommands
2969
2970
2971 def GetCommands(self):
2972 """
2973 Returns the list of commands.
2974 """
2975 return self._commands
2976
2977
2978 def ClearCommands(self):
2979 """
2980 Deletes all the commands in the list and sets the current command
2981 pointer to None.
2982 """
2983 self._commands = []
2984 self._redoCommands = []
2985
2986
2987 def GetEditMenu(self):
2988 """
2989 Returns the edit menu associated with the command processor.
2990 """
2991 return self._editMenu
2992
2993
2994 def SetEditMenu(self, menu):
2995 """
2996 Tells the command processor to update the Undo and Redo items on this
2997 menu as appropriate. Set this to NULL if the menu is about to be
2998 destroyed and command operations may still be performed, or the
2999 command processor may try to access an invalid pointer.
3000 """
3001 self._editMenu = menu
3002
3003
3004 def GetUndoAccelerator(self):
3005 """
3006 Returns the string that will be appended to the Undo menu item.
3007 """
3008 return self._undoAccelerator
3009
3010
3011 def SetUndoAccelerator(self, accel):
3012 """
3013 Sets the string that will be appended to the Redo menu item.
3014 """
3015 self._undoAccelerator = accel
3016
3017
3018 def GetRedoAccelerator(self):
3019 """
3020 Returns the string that will be appended to the Redo menu item.
3021 """
3022 return self._redoAccelerator
3023
3024
3025 def SetRedoAccelerator(self, accel):
3026 """
3027 Sets the string that will be appended to the Redo menu item.
3028 """
3029 self._redoAccelerator = accel
3030
3031
3032 def SetEditMenu(self, menu):
3033 """
3034 Tells the command processor to update the Undo and Redo items on this
3035 menu as appropriate. Set this to NULL if the menu is about to be
3036 destroyed and command operations may still be performed, or the
3037 command processor may try to access an invalid pointer.
3038 """
3039 self._editMenu = menu
3040
3041
3042 def SetMenuStrings(self):
3043 """
3044 Sets the menu labels according to the currently set menu and the
3045 current command state.
3046 """
3047 if self.GetEditMenu() != None:
3048 undoCommand = self._GetCurrentCommand()
3049 redoCommand = self._GetCurrentRedoCommand()
3050 undoItem = self.GetEditMenu().FindItemById(wx.ID_UNDO)
3051 redoItem = self.GetEditMenu().FindItemById(wx.ID_REDO)
3052 if self.GetUndoAccelerator():
3053 undoAccel = '\t' + self.GetUndoAccelerator()
3054 else:
3055 undoAccel = ''
3056 if self.GetRedoAccelerator():
3057 redoAccel = '\t' + self.GetRedoAccelerator()
3058 else:
3059 redoAccel = ''
3060 if undoCommand and undoItem and undoCommand.CanUndo():
3061 undoItem.SetText(_("Undo ") + undoCommand.GetName() + undoAccel)
3062 #elif undoCommand and not undoCommand.CanUndo():
3063 # undoItem.SetText(_("Can't Undo") + undoAccel)
3064 else:
3065 undoItem.SetText(_("Undo" + undoAccel))
3066 if redoCommand and redoItem:
3067 redoItem.SetText(_("Redo ") + redoCommand.GetName() + redoAccel)
3068 else:
3069 redoItem.SetText(_("Redo") + redoAccel)
3070
3071
3072 def CanUndo(self):
3073 """
3074 Returns true if the currently-active command can be undone, false
3075 otherwise.
3076 """
3077 if self._GetCurrentCommand() == None:
3078 return False
3079 return self._GetCurrentCommand().CanUndo()
3080
3081
3082 def CanRedo(self):
3083 """
3084 Returns true if the currently-active command can be redone, false
3085 otherwise.
3086 """
3087 return self._GetCurrentRedoCommand() != None
3088
3089
3090 def Submit(self, command, storeIt=True):
3091 """
3092 Submits a new command to the command processor. The command processor
3093 calls wxCommand::Do to execute the command; if it succeeds, the
3094 command is stored in the history list, and the associated edit menu
3095 (if any) updated appropriately. If it fails, the command is deleted
3096 immediately. Once Submit has been called, the passed command should
3097 not be deleted directly by the application.
3098
3099 storeIt indicates whether the successful command should be stored in
3100 the history list.
3101 """
3102 done = command.Do()
3103 if done and storeIt:
3104 self._commands.append(command)
3105 if self._maxCommands > -1:
3106 if len(self._commands) > self._maxCommands:
3107 del self._commands[0]
3108 return done
3109
3110
3111 def Redo(self):
3112 """
3113 Redoes the command just undone.
3114 """
3115 cmd = self._GetCurrentRedoCommand()
3116 if not cmd:
3117 return False
3118 done = cmd.Do()
3119 if done:
3120 self._commands.append(self._redoCommands.pop())
3121 return done
3122
3123
3124 def Undo(self):
3125 """
3126 Undoes the command just executed.
3127 """
3128 cmd = self._GetCurrentCommand()
3129 if not cmd:
3130 return False
3131 done = cmd.Undo()
3132 if done:
3133 self._redoCommands.append(self._commands.pop())
3134 return done
3135
3136