~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to wxPython/wx/lib/docview.py

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

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