...
[iramuteq] / aui / tabmdi.py
1 __author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
2 __date__ = "31 March 2009"
3
4
5 import wx
6
7 import auibook
8 from aui_constants import *
9
10 _ = wx.GetTranslation
11
12 #-----------------------------------------------------------------------------
13 # AuiMDIParentFrame
14 #-----------------------------------------------------------------------------
15
16 class AuiMDIParentFrame(wx.Frame):
17
18     def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
19                  size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE|wx.VSCROLL|wx.HSCROLL,
20                  name="AuiMDIParentFrame"):
21
22         wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
23         self.Init()
24
25         self.Bind(wx.EVT_MENU, self.DoHandleMenu, id=wx.ID_ANY)
26
27         # this style can be used to prevent a window from having the standard MDI
28         # "Window" menu
29         if not style & wx.FRAME_NO_WINDOW_MENU:
30         
31             self._pWindowMenu = wx.Menu()
32             self._pWindowMenu.Append(wxWINDOWCLOSE,    _("Cl&ose"))
33             self._pWindowMenu.Append(wxWINDOWCLOSEALL, _("Close All"))
34             self._pWindowMenu.AppendSeparator()
35             self._pWindowMenu.Append(wxWINDOWNEXT,     _("&Next"))
36             self._pWindowMenu.Append(wxWINDOWPREV,     _("&Previous"))
37     
38         self._pClientWindow = self.OnCreateClient()
39
40
41     def SetArtProvider(self, provider):
42
43         if self._pClientWindow:
44             self._pClientWindow.SetArtProvider(provider)
45     
46
47     def GetArtProvider(self):
48
49         if not self._pClientWindow:
50             return None
51
52         return self._pClientWindow.GetArtProvider()
53
54
55     def GetNotebook(self):
56
57         return self._pClientWindow
58
59
60     def SetWindowMenu(self, pMenu):
61
62         # Replace the window menu from the currently loaded menu bar.
63         pMenuBar = self.GetMenuBar()
64
65         if self._pWindowMenu:
66             self.RemoveWindowMenu(pMenuBar)
67             del self._pWindowMenu
68             self._pWindowMenu = None
69
70         if pMenu:
71             self._pWindowMenu = pMenu
72             self.AddWindowMenu(pMenuBar)
73         
74
75     def GetWindowMenu(self):
76
77         return self._pWindowMenu
78     
79
80     def SetMenuBar(self, pMenuBar):
81
82         # Remove the Window menu from the old menu bar
83         self.RemoveWindowMenu(self.GetMenuBar())
84
85         # Add the Window menu to the new menu bar.
86         self.AddWindowMenu(pMenuBar)
87
88         wx.Frame.SetMenuBar(self, pMenuBar)
89
90
91     def SetChildMenuBar(self, pChild):
92
93         if not pChild:
94         
95             # No Child, set Our menu bar back.
96             if self._pMyMenuBar:
97                 self.SetMenuBar(self._pMyMenuBar)
98             else:
99                 self.SetMenuBar(self.GetMenuBar())
100
101             # Make sure we know our menu bar is in use
102             self._pMyMenuBar = None
103         
104         else:
105         
106             if pChild.GetMenuBar() == None:
107                 return
108
109             # Do we need to save the current bar?
110             if self._pMyMenuBar == None:
111                 self._pMyMenuBar = self.GetMenuBar()
112
113             self.SetMenuBar(pChild.GetMenuBar())
114     
115
116     def ProcessEvent(self, event):
117
118         # stops the same event being processed repeatedly
119         if self._pLastEvt == event:
120             return False
121         
122         self._pLastEvt = event
123
124         # let the active child (if any) process the event first.
125         res = False
126         if self._pActiveChild and event.IsCommandEvent() and \
127            event.GetEventObject() != self._pClientWindow and \
128            event.GetEventType() not in [wx.wxEVT_ACTIVATE, wx.wxEVT_SET_FOCUS,
129                                         wx.wxEVT_KILL_FOCUS, wx.wxEVT_CHILD_FOCUS,
130                                         wx.wxEVT_COMMAND_SET_FOCUS, wx.wxEVT_COMMAND_KILL_FOCUS]:
131         
132             res = self._pActiveChild.GetEventHandler().ProcessEvent(event)
133         
134         if not res:
135         
136             # if the event was not handled this frame will handle it,
137             # which is why we need the protection code at the beginning
138             # of this method
139             res = self.GetEventHandler().ProcessEvent(event)
140         
141         self._pLastEvt = None
142
143         return res
144
145
146     def GetActiveChild(self):
147
148         return self._pActiveChild
149
150
151     def SetActiveChild(self, pChildFrame):
152
153         self._pActiveChild = pChildFrame
154
155
156     def GetClientWindow(self):
157
158         return self._pClientWindow
159
160
161     def OnCreateClient(self):
162
163         return AuiMDIClientWindow(self)
164
165
166     def ActivateNext(self):
167
168         if self._pClientWindow and self._pClientWindow.GetSelection() != wx.NOT_FOUND:
169         
170             active = self._pClientWindow.GetSelection() + 1
171             if active >= self._pClientWindow.GetPageCount():
172                 active = 0
173
174             self._pClientWindow.SetSelection(active)
175         
176
177     def ActivatePrevious(self):
178
179         if self._pClientWindow and self._pClientWindow.GetSelection() != wx.NOT_FOUND:
180         
181             active = self._pClientWindow.GetSelection() - 1
182             if active < 0:
183                 active = self._pClientWindow.GetPageCount() - 1
184
185             self._pClientWindow.SetSelection(active)
186     
187
188     def Init(self):
189
190         self._pLastEvt = None
191
192         self._pClientWindow = None
193         self._pActiveChild = None
194         self._pWindowMenu = None
195         self._pMyMenuBar = None
196
197
198     def RemoveWindowMenu(self, pMenuBar):
199
200         if pMenuBar and self._pWindowMenu:
201         
202             # Remove old window menu
203             pos = pMenuBar.FindMenu(_("&Window"))
204             if pos != wx.NOT_FOUND:            
205                 pMenuBar.Remove(pos)
206             
207
208     def AddWindowMenu(self, pMenuBar):
209
210         if pMenuBar and self._pWindowMenu:
211         
212             pos = pMenuBar.FindMenu(wx.GetStockLabel(wx.ID_HELP, wx.STOCK_NOFLAGS))
213             if pos == wx.NOT_FOUND:
214                 pMenuBar.Append(self._pWindowMenu, _("&Window"))
215             else:
216                 pMenuBar.Insert(pos, self._pWindowMenu, _("&Window"))
217     
218
219     def DoHandleMenu(self, event):
220
221         evId = event.GetId()
222         
223         if evId == wxWINDOWCLOSE:
224             if self._pActiveChild:
225                 self._pActiveChild.Close()
226
227         elif evId == wxWINDOWCLOSEALL:
228             
229             while self._pActiveChild:            
230                 if not self._pActiveChild.Close():
231                     return # failure
232                 
233         elif evId == wxWINDOWNEXT:
234             self.ActivateNext()
235
236         elif evId == wxWINDOWPREV:
237             self.ActivatePrevious()
238
239         else:
240             event.Skip()
241
242     
243     def Tile(self, orient=wx.HORIZONTAL):
244
245         client_window = self.GetClientWindow()
246         if not client_window:
247             raise Exception("Missing MDI Client Window")
248
249         cur_idx = client_window.GetSelection()
250         if cur_idx == -1:
251             return
252
253         if orient == wx.VERTICAL:
254         
255             client_window.Split(cur_idx, wx.LEFT)
256         
257         elif orient == wx.HORIZONTAL:
258         
259             client_window.Split(cur_idx, wx.TOP)
260     
261
262 #-----------------------------------------------------------------------------
263 # AuiMDIChildFrame
264 #-----------------------------------------------------------------------------
265
266 class AuiMDIChildFrame(wx.PyPanel):
267
268     def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
269                  size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="AuiMDIChildFrame"):
270
271         pClientWindow = parent.GetClientWindow()
272         if pClientWindow is None:
273             raise Exception("Missing MDI client window.")
274
275         self.Init()
276         
277         # see comment in constructor
278         if style & wx.MINIMIZE:
279             self._activate_on_create = False
280
281         cli_size = pClientWindow.GetClientSize()
282
283         # create the window off-screen to prevent flicker
284         wx.PyPanel.__init__(self, pClientWindow, id, wx.Point(cli_size.x+1, cli_size.y+1),
285                             size, wx.NO_BORDER, name=name)
286
287         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
288         self.Show(False)
289         self.SetMDIParentFrame(parent)
290
291         # this is the currently active child
292         parent.SetActiveChild(self)
293         self._title = title
294
295         pClientWindow.AddPage(self, title, self._activate_on_create)
296         pClientWindow.Refresh()
297
298         self.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuHighlight)
299         self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
300         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
301
302
303     def Init(self):
304
305         # There are two ways to create an tabbed mdi child fram without
306         # making it the active document.  Either Show(False) can be called
307         # before Create() (as is customary on some ports with wxFrame-type
308         # windows), or wx.MINIMIZE can be passed in the style flags.  Note that
309         # AuiMDIChildFrame is not really derived from wxFrame, as MDIChildFrame
310         # is, but those are the expected symantics.  No style flag is passed
311         # onto the panel underneath.
312
313         self._activate_on_create = True
314
315         self._pMDIParentFrame = None
316         self._pMenuBar = None
317         
318         self._mdi_currect = None
319         self._mdi_newrect = wx.Rect()
320         self._icon = None
321         self._icon_bundle = None
322
323
324     def Destroy(self):
325
326         pParentFrame = self.GetMDIParentFrame()
327         if not pParentFrame:
328             raise Exception("Missing MDI Parent Frame")
329
330         pClientWindow = pParentFrame.GetClientWindow()
331         if not pClientWindow:
332             raise Exception("Missing MDI Client Window")
333
334         if pParentFrame.GetActiveChild() == self:
335         
336             # deactivate ourself
337             event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, False, self.GetId())
338             event.SetEventObject(self)
339             self.GetEventHandler().ProcessEvent(event)
340
341             pParentFrame.SetActiveChild(None)
342             pParentFrame.SetChildMenuBar(None)
343         
344         for pos in xrange(pClientWindow.GetPageCount()):
345             if pClientWindow.GetPage(pos) == self:
346                 return pClientWindow.DeletePage(pos)
347
348         return False
349
350
351     def SetMenuBar(self, menu_bar):
352
353         pOldMenuBar = self._pMenuBar
354         self._pMenuBar = menu_bar
355
356         if self._pMenuBar:
357         
358             pParentFrame = self.GetMDIParentFrame()
359             if not pParentFrame:
360                 raise Exception("Missing MDI Parent Frame")
361
362             self._pMenuBar.Reparent(pParentFrame)
363             if pParentFrame.GetActiveChild() == self:
364             
365                 # replace current menu bars
366                 if pOldMenuBar:
367                     pParentFrame.SetChildMenuBar(None)
368                     
369                 pParentFrame.SetChildMenuBar(self)
370             
371
372     def GetMenuBar(self):
373
374         return self._pMenuBar
375
376
377     def SetTitle(self, title):
378
379         self._title = title
380
381         pParentFrame = self.GetMDIParentFrame()
382         if not pParentFrame:
383             raise Exception("Missing MDI Parent Frame")
384         
385         pClientWindow = pParentFrame.GetClientWindow()
386         if pClientWindow is not None:
387         
388             for pos in xrange(pClientWindow.GetPageCount()):
389                 if pClientWindow.GetPage(pos) == self:
390                     pClientWindow.SetPageText(pos, self._title)
391                     break
392
393
394     def GetTitle(self):
395
396         return self._title
397
398
399     def SetIcons(self, icons):
400
401         # get icon with the system icon size
402         self.SetIcon(icons.GetIcon(-1))
403         self._icon_bundle = icons
404
405
406     def GetIcons(self):
407
408         return self._icon_bundle
409
410
411     def SetIcon(self, icon):
412
413         pParentFrame = self.GetMDIParentFrame()
414         if not pParentFrame:
415             raise Exception("Missing MDI Parent Frame")
416
417         self._icon = icon
418
419         bmp = wx.BitmapFromIcon(self._icon)
420
421         pClientWindow = pParentFrame.GetClientWindow()
422         if pClientWindow is not None:
423             idx = pClientWindow.GetPageIndex(self)
424             if idx != -1:
425                 pClientWindow.SetPageBitmap(idx, bmp)
426         
427
428     def GetIcon(self):
429
430         return self._icon
431
432
433     def Activate(self):
434
435         pParentFrame = self.GetMDIParentFrame()
436         if not pParentFrame:
437             raise Exception("Missing MDI Parent Frame")
438         
439         pClientWindow = pParentFrame.GetClientWindow()
440         if pClientWindow is not None:
441         
442             for pos in xrange(pClientWindow.GetPageCount()):
443                 if pClientWindow.GetPage(pos) == self:
444                     pClientWindow.SetSelection(pos)
445                     break
446             
447
448     def OnMenuHighlight(self, event):
449
450         if self._pMDIParentFrame:
451     
452             # we don't have any help text for this item,
453             # but may be the MDI frame does?
454             self._pMDIParentFrame.OnMenuHighlight(event)
455
456
457     def OnActivate(self, event):
458
459         # do nothing
460         pass
461
462
463     def OnCloseWindow(self, event):
464
465         pParentFrame = self.GetMDIParentFrame()
466         if pParentFrame:
467             if pParentFrame.GetActiveChild() == self:
468             
469                 pParentFrame.SetActiveChild(None)
470                 pParentFrame.SetChildMenuBar(None)
471             
472             pClientWindow = pParentFrame.GetClientWindow()
473             idx = pClientWindow.GetPageIndex(self)
474             
475             if idx != wx.NOT_FOUND:
476                 pClientWindow.RemovePage(idx)
477
478         self.Destroy()
479
480
481     def SetMDIParentFrame(self, parentFrame):
482
483         self._pMDIParentFrame = parentFrame
484
485
486     def GetMDIParentFrame(self):
487
488         return self._pMDIParentFrame
489
490
491     def CreateStatusBar(self, number=1, style=1, winid=1, name=""):
492         
493         return None
494
495
496     def GetStatusBar(self):
497
498         return None
499     
500
501     def SetStatusText(self, text, number=0):
502
503         pass
504
505     
506     def SetStatusWidths(self, widths_field):
507
508         pass
509     
510
511     # no toolbar bars
512     def CreateToolBar(self, style=1, winid=-1, name=""):
513         
514         return None
515
516     
517     def GetToolBar(self):
518
519         return None
520     
521
522     # no maximize etc
523     def Maximize(self, maximize=True):
524
525         pass
526
527
528     def Restore(self):
529     
530         pass
531
532     
533     def Iconize(self, iconize=True):
534
535         pass
536
537     
538     def IsMaximized(self):
539
540         return True
541
542     
543     def IsIconized(self):
544
545         return False
546
547     
548     def ShowFullScreen(self, show=True, style=0):
549
550         return False
551
552     
553     def IsFullScreen(self):
554
555         return False        
556
557
558     def IsTopLevel(self):
559
560         return False
561
562
563     # renamed from Show().
564     def ActivateOnCreate(self, activate_on_create):
565
566         self._activate_on_create = activate_on_create
567         return True
568
569     
570     def Show(self, show=True):
571
572         wx.PyPanel.Show(self, show)
573
574
575     def ApplyMDIChildFrameRect(self):
576
577         if self._mdi_currect != self._mdi_newrect:
578             self.SetDimensions(*self._mdi_newrect)
579             self._mdi_currect = wx.Rect(*self._mdi_newrect)
580
581
582 #-----------------------------------------------------------------------------
583 # AuiMDIClientWindow
584 #-----------------------------------------------------------------------------
585
586 class AuiMDIClientWindow(auibook.AuiNotebook):
587
588     def __init__(self, parent, agwStyle=0):
589
590         auibook.AuiNotebook.__init__(self, parent, wx.ID_ANY, wx.Point(0, 0), wx.Size(100, 100),
591                                      agwStyle=AUI_NB_DEFAULT_STYLE|wx.NO_BORDER)
592
593         caption_icon_size = wx.Size(wx.SystemSettings.GetMetric(wx.SYS_SMALLICON_X),
594                                     wx.SystemSettings.GetMetric(wx.SYS_SMALLICON_Y))
595         self.SetUniformBitmapSize(caption_icon_size)
596
597         bkcolour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_APPWORKSPACE)
598         self.SetOwnBackgroundColour(bkcolour)
599
600         self._mgr.GetArtProvider().SetColour(AUI_DOCKART_BACKGROUND_COLOUR, bkcolour)
601
602         self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnPageChanged)
603         self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnPageClose)
604         self.Bind(wx.EVT_SIZE, self.OnSize)
605
606
607     def SetSelection(self, nPage):
608
609         return auibook.AuiNotebook.SetSelection(self, nPage)
610
611
612     def PageChanged(self, old_selection, new_selection):
613
614         # don't do anything if the page doesn't actually change
615         if old_selection == new_selection:
616             return
617
618         # notify old active child that it has been deactivated
619         if old_selection != -1 and old_selection < self.GetPageCount():
620         
621             old_child = self.GetPage(old_selection)
622             if not old_child:
623                 raise Exception("AuiMDIClientWindow.PageChanged - null page pointer")
624
625             event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, False, old_child.GetId())
626             event.SetEventObject(old_child)
627             old_child.GetEventHandler().ProcessEvent(event)
628         
629         # notify new active child that it has been activated
630         if new_selection != -1:
631         
632             active_child = self.GetPage(new_selection)
633             if not active_child:
634                 raise Exception("AuiMDIClientWindow.PageChanged - null page pointer")
635
636             event = wx.ActivateEvent(wx.wxEVT_ACTIVATE, True, active_child.GetId())
637             event.SetEventObject(active_child)
638             active_child.GetEventHandler().ProcessEvent(event)
639
640             if active_child.GetMDIParentFrame():
641                 active_child.GetMDIParentFrame().SetActiveChild(active_child)
642                 active_child.GetMDIParentFrame().SetChildMenuBar(active_child)
643
644
645     def OnPageClose(self, event):
646
647         wnd = self.GetPage(event.GetSelection())
648         wnd.Close()
649
650         # regardless of the result of wnd.Close(), we've
651         # already taken care of the close operations, so
652         # suppress further processing
653         event.Veto()
654
655
656     def OnPageChanged(self, event):
657
658         self.PageChanged(event.GetOldSelection(), event.GetSelection())
659
660
661     def OnSize(self, event):
662
663         auibook.AuiNotebook.OnSize(self, event)
664
665         for pos in xrange(self.GetPageCount()):
666             self.GetPage(pos).ApplyMDIChildFrameRect()