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