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