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