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