+ if size == wx.DefaultSize:
+ size = wx.Size(config.ReadInt("MDIFrameXSize", 450), config.ReadInt("MDIFrameYSize", 300))
+ return pos, size
+
+
+ def _InitFrame(self, embeddedWindows, minSize):
+ """
+ Initializes the frame and creates the default menubar, toolbar, and status bar.
+ """
+ self._embeddedWindows = []
+ self.SetDropTarget(_DocFrameFileDropTarget(self._docManager, self))
+
+ if wx.GetApp().GetDefaultIcon():
+ self.SetIcon(wx.GetApp().GetDefaultIcon())
+
+ wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout)
+ wx.EVT_SIZE(self, self.OnSize)
+
+ self.InitializePrintData()
+
+ toolBar = self.CreateDefaultToolBar()
+ self.SetToolBar(toolBar)
+ menuBar = self.CreateDefaultMenuBar()
+ statusBar = self.CreateDefaultStatusBar()
+
+ config = wx.ConfigBase_Get()
+ if config.ReadInt("MDIFrameMaximized", False):
+ # wxBug: On maximize, statusbar leaves a residual that needs to be refereshed, happens even when user does it
+ self.Maximize()
+
+ self.CreateEmbeddedWindows(embeddedWindows, minSize)
+ self._LayoutFrame()
+
+ if wx.Platform == '__WXMAC__':
+ self.SetMenuBar(menuBar) # wxBug: Have to set the menubar at the very end or the automatic MDI "window" menu doesn't get put in the right place when the services add new menus to the menubar
+
+ wx.GetApp().SetTopWindow(self) # Need to do this here in case the services are looking for wx.GetApp().GetTopWindow()
+ for service in wx.GetApp().GetServices():
+ service.InstallControls(self, menuBar = menuBar, toolBar = toolBar, statusBar = statusBar)
+ if hasattr(service, "ShowWindow"):
+ service.ShowWindow() # instantiate service windows for correct positioning, we'll hide/show them later based on user preference
+
+ if wx.Platform != '__WXMAC__':
+ self.SetMenuBar(menuBar) # wxBug: Have to set the menubar at the very end or the automatic MDI "window" menu doesn't get put in the right place when the services add new menus to the menubar
+
+
+ def ProcessEvent(self, event):
+ """
+ Processes an event, searching event tables and calling zero or more
+ suitable event handler function(s). Note that the ProcessEvent
+ method is called from the wxPython docview framework directly since
+ wxPython does not have a virtual ProcessEvent function.
+ """
+ id = event.GetId()
+ if id == SAVEALL_ID:
+ self.OnFileSaveAll(event)
+ return True
+
+ return wx.GetApp().ProcessEvent(event)
+
+
+ def ProcessUpdateUIEvent(self, event):
+ """
+ Processes a UI event, searching event tables and calling zero or more
+ suitable event handler function(s). Note that the ProcessEvent
+ method is called from the wxPython docview framework directly since
+ wxPython does not have a virtual ProcessEvent function.
+ """
+ id = event.GetId()
+ if id == wx.ID_CUT:
+ event.Enable(False)
+ return True
+ elif id == wx.ID_COPY:
+ event.Enable(False)
+ return True
+ elif id == wx.ID_PASTE:
+ event.Enable(False)
+ return True
+ elif id == wx.ID_CLEAR:
+ event.Enable(False)
+ return True
+ elif id == wx.ID_SELECTALL:
+ event.Enable(False)
+ return True
+ elif id == SAVEALL_ID:
+ filesModified = False
+ docs = wx.GetApp().GetDocumentManager().GetDocuments()
+ for doc in docs:
+ if doc.IsModified():
+ filesModified = True
+ break
+
+ event.Enable(filesModified)
+ return True
+ else:
+ return wx.GetApp().ProcessUpdateUIEvent(event)
+
+
+ def CreateEmbeddedWindows(self, windows=0, minSize=20):
+ """
+ Create the specified embedded windows around the edges of the frame.
+ """
+ frameSize = self.GetSize() # TODO: GetClientWindow.GetSize is still returning 0,0 since the frame isn't fully constructed yet, so using full frame size
+ defaultHSize = max(minSize, int(frameSize[0] / 6))
+ defaultVSize = max(minSize, int(frameSize[1] / 7))
+ defaultSubVSize = int(frameSize[1] / 2)
+ config = wx.ConfigBase_Get()
+ if windows & (EMBEDDED_WINDOW_LEFT | EMBEDDED_WINDOW_TOPLEFT | EMBEDDED_WINDOW_BOTTOMLEFT):
+ self._leftEmbWindow = self._CreateEmbeddedWindow(self, (max(minSize,config.ReadInt("MDIEmbedLeftSize", defaultHSize)), -1), wx.LAYOUT_VERTICAL, wx.LAYOUT_LEFT, visible = config.ReadInt("MDIEmbedLeftVisible", 1), sash = wx.SASH_RIGHT)
+ else:
+ self._leftEmbWindow = None
+ if windows & EMBEDDED_WINDOW_TOPLEFT:
+ self._topLeftEmbWindow = self._CreateEmbeddedWindow(self._leftEmbWindow, (-1, config.ReadInt("MDIEmbedTopLeftSize", defaultSubVSize)), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_TOP, visible = config.ReadInt("MDIEmbedTopLeftVisible", 1), sash = wx.SASH_BOTTOM)
+ else:
+ self._topLeftEmbWindow = None
+ if windows & EMBEDDED_WINDOW_BOTTOMLEFT:
+ self._bottomLeftEmbWindow = self._CreateEmbeddedWindow(self._leftEmbWindow, (-1, config.ReadInt("MDIEmbedBottomLeftSize", defaultSubVSize)), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_BOTTOM, visible = config.ReadInt("MDIEmbedBottomLeftVisible", 1))
+ else:
+ self._bottomLeftEmbWindow = None
+ if windows & (EMBEDDED_WINDOW_RIGHT | EMBEDDED_WINDOW_TOPRIGHT | EMBEDDED_WINDOW_BOTTOMRIGHT):
+ self._rightEmbWindow = self._CreateEmbeddedWindow(self, (max(minSize,config.ReadInt("MDIEmbedRightSize", defaultHSize)), -1), wx.LAYOUT_VERTICAL, wx.LAYOUT_RIGHT, visible = config.ReadInt("MDIEmbedRightVisible", 1), sash = wx.SASH_LEFT)
+ else:
+ self._rightEmbWindow = None
+ if windows & EMBEDDED_WINDOW_TOPRIGHT:
+ self._topRightEmbWindow = self._CreateEmbeddedWindow(self._rightEmbWindow, (-1, config.ReadInt("MDIEmbedTopRightSize", defaultSubVSize)), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_TOP, visible = config.ReadInt("MDIEmbedTopRightVisible", 1), sash = wx.SASH_BOTTOM)
+ else:
+ self._topRightEmbWindow = None
+ if windows & EMBEDDED_WINDOW_BOTTOMRIGHT:
+ self._bottomRightEmbWindow = self._CreateEmbeddedWindow(self._rightEmbWindow, (-1, config.ReadInt("MDIEmbedBottomRightSize", defaultSubVSize)), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_BOTTOM, visible = config.ReadInt("MDIEmbedBottomRightVisible", 1))
+ else:
+ self._bottomRightEmbWindow = None
+ if windows & EMBEDDED_WINDOW_TOP:
+ self._topEmbWindow = self._CreateEmbeddedWindow(self, (-1, max(minSize,config.ReadInt("MDIEmbedTopSize", defaultVSize))), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_TOP, visible = config.ReadInt("MDIEmbedTopVisible", 1), sash = wx.SASH_BOTTOM)
+ else:
+ self._topEmbWindow = None
+ if windows & EMBEDDED_WINDOW_BOTTOM:
+ self._bottomEmbWindow = self._CreateEmbeddedWindow(self, (-1, max(minSize,config.ReadInt("MDIEmbedBottomSize", defaultVSize))), wx.LAYOUT_HORIZONTAL, wx.LAYOUT_BOTTOM, visible = config.ReadInt("MDIEmbedBottomVisible", 1), sash = wx.SASH_TOP)
+ else:
+ self._bottomEmbWindow = None
+
+
+ def SaveEmbeddedWindowSizes(self):
+ """
+ Saves the sizes of the embedded windows.
+ """
+ config = wx.ConfigBase_Get()
+ if not self.IsMaximized():
+ config.WriteInt("MDIFrameXLoc", self.GetPositionTuple()[0])
+ config.WriteInt("MDIFrameYLoc", self.GetPositionTuple()[1])
+ config.WriteInt("MDIFrameXSize", self.GetSizeTuple()[0])
+ config.WriteInt("MDIFrameYSize", self.GetSizeTuple()[1])
+ config.WriteInt("MDIFrameMaximized", self.IsMaximized())
+ config.WriteInt("ViewToolBar", self._toolBar.IsShown())
+ config.WriteInt("ViewStatusBar", self.GetStatusBar().IsShown())
+
+ if self._leftEmbWindow:
+ config.WriteInt("MDIEmbedLeftSize", self._leftEmbWindow.GetSize()[0])
+ config.WriteInt("MDIEmbedLeftVisible", self._leftEmbWindow.IsShown())
+ if self._topLeftEmbWindow:
+ if self._topLeftEmbWindow._sizeBeforeHidden:
+ size = self._topLeftEmbWindow._sizeBeforeHidden[1]
+ else:
+ size = self._topLeftEmbWindow.GetSize()[1]
+ config.WriteInt("MDIEmbedTopLeftSize", size)
+ config.WriteInt("MDIEmbedTopLeftVisible", self._topLeftEmbWindow.IsShown())
+ if self._bottomLeftEmbWindow:
+ if self._bottomLeftEmbWindow._sizeBeforeHidden:
+ size = self._bottomLeftEmbWindow._sizeBeforeHidden[1]
+ else:
+ size = self._bottomLeftEmbWindow.GetSize()[1]
+ config.WriteInt("MDIEmbedBottomLeftSize", size)
+ config.WriteInt("MDIEmbedBottomLeftVisible", self._bottomLeftEmbWindow.IsShown())
+ if self._rightEmbWindow:
+ config.WriteInt("MDIEmbedRightSize", self._rightEmbWindow.GetSize()[0])
+ config.WriteInt("MDIEmbedRightVisible", self._rightEmbWindow.IsShown())
+ if self._topRightEmbWindow:
+ if self._topRightEmbWindow._sizeBeforeHidden:
+ size = self._topRightEmbWindow._sizeBeforeHidden[1]
+ else:
+ size = self._topRightEmbWindow.GetSize()[1]
+ config.WriteInt("MDIEmbedTopRightSize", size)
+ config.WriteInt("MDIEmbedTopRightVisible", self._topRightEmbWindow.IsShown())
+ if self._bottomRightEmbWindow:
+ if self._bottomRightEmbWindow._sizeBeforeHidden:
+ size = self._bottomRightEmbWindow._sizeBeforeHidden[1]
+ else:
+ size = self._bottomRightEmbWindow.GetSize()[1]
+ config.WriteInt("MDIEmbedBottomRightSize", size)
+ config.WriteInt("MDIEmbedBottomRightVisible", self._bottomRightEmbWindow.IsShown())
+ if self._topEmbWindow:
+ config.WriteInt("MDIEmbedTopSize", self._topEmbWindow.GetSize()[1])
+ config.WriteInt("MDIEmbedTopVisible", self._topEmbWindow.IsShown())
+ if self._bottomEmbWindow:
+ config.WriteInt("MDIEmbedBottomSize", self._bottomEmbWindow.GetSize()[1])
+ config.WriteInt("MDIEmbedBottomVisible", self._bottomEmbWindow.IsShown())
+
+
+ def GetEmbeddedWindow(self, loc):
+ """
+ Returns the instance of the embedded window specified by the embedded window location constant.
+ """
+ if loc == EMBEDDED_WINDOW_TOP:
+ return self._topEmbWindow
+ elif loc == EMBEDDED_WINDOW_BOTTOM:
+ return self._bottomEmbWindow
+ elif loc == EMBEDDED_WINDOW_LEFT:
+ return self._leftEmbWindow
+ elif loc == EMBEDDED_WINDOW_RIGHT:
+ return self._rightEmbWindow
+ elif loc == EMBEDDED_WINDOW_TOPLEFT:
+ return self._topLeftEmbWindow
+ elif loc == EMBEDDED_WINDOW_BOTTOMLEFT:
+ return self._bottomLeftEmbWindow
+ elif loc == EMBEDDED_WINDOW_TOPRIGHT:
+ return self._topRightEmbWindow
+ elif loc == EMBEDDED_WINDOW_BOTTOMRIGHT:
+ return self._bottomRightEmbWindow
+ return None
+
+
+ def _CreateEmbeddedWindow(self, parent, size, orientation, alignment, visible=True, sash=None):
+ """
+ Creates the embedded window with the specified size, orientation, and alignment. If the
+ window is not visible it will retain the size with which it was last viewed.
+ """
+ window = wx.SashLayoutWindow(parent, wx.NewId(), style = wx.NO_BORDER | wx.SW_3D)
+ window.SetDefaultSize(size)
+ window.SetOrientation(orientation)
+ window.SetAlignment(alignment)
+ if sash != None: # wx.SASH_TOP is 0 so check for None instead of just doing "if sash:"
+ window.SetSashVisible(sash, True)
+ ####
+ def OnEmbeddedWindowSashDrag(event):
+ if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE:
+ return
+ sashWindow = event.GetEventObject()
+ if sashWindow.GetAlignment() == wx.LAYOUT_TOP or sashWindow.GetAlignment() == wx.LAYOUT_BOTTOM:
+ size = wx.Size(-1, event.GetDragRect().height)
+ else:
+ size = wx.Size(event.GetDragRect().width, -1)
+ event.GetEventObject().SetDefaultSize(size)
+ self._LayoutFrame()
+ sashWindow.Refresh()
+ if isinstance(sashWindow.GetParent(), wx.SashLayoutWindow):
+ sashWindow.Show()
+ parentSashWindow = sashWindow.GetParent() # Force a refresh
+ parentSashWindow.Layout()
+ parentSashWindow.Refresh()
+ parentSashWindow.SetSize((parentSashWindow.GetSize().width + 1, parentSashWindow.GetSize().height + 1))
+ ####
+ wx.EVT_SASH_DRAGGED(window, window.GetId(), OnEmbeddedWindowSashDrag)
+ window._sizeBeforeHidden = None
+ if not visible:
+ window.Show(False)
+ if isinstance(parent, wx.SashLayoutWindow): # It's a window embedded in another sash window so remember its actual size to show it again
+ window._sizeBeforeHidden = size
+ return window
+
+
+ def ShowEmbeddedWindow(self, window, show=True):
+ """
+ Shows or hides the embedded window specified by the embedded window location constant.
+ """
+ window.Show(show)
+ if isinstance(window.GetParent(), wx.SashLayoutWindow): # It is a parent sashwindow with multiple embedded sashwindows
+ parentSashWindow = window.GetParent()
+ if show: # Make sure it is visible in case all of the subwindows were hidden
+ parentSashWindow.Show()
+ if show and window._sizeBeforeHidden:
+ if window._sizeBeforeHidden[1] == parentSashWindow.GetClientSize()[1]:
+ if window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT) and self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT).IsShown():
+ window.SetDefaultSize((window._sizeBeforeHidden[0], window._sizeBeforeHidden[0] - self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT).GetSize()[1]))
+ elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT) and self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT).IsShown():
+ window.SetDefaultSize((window._sizeBeforeHidden[0], window._sizeBeforeHidden[0] - self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT).GetSize()[1]))
+ elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT) and self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT).IsShown():
+ window.SetDefaultSize((window._sizeBeforeHidden[0], window._sizeBeforeHidden[0] - self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT).GetSize()[1]))
+ elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT) and self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT).IsShown():
+ window.SetDefaultSize((window._sizeBeforeHidden[0], window._sizeBeforeHidden[0] - self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT).GetSize()[1]))
+ else:
+ window.SetDefaultSize(window._sizeBeforeHidden)
+ # If it is not the size of the full parent sashwindow set the other window's size so that if it gets shown it will have a cooresponding size
+ if window._sizeBeforeHidden[1] < parentSashWindow.GetClientSize()[1]:
+ otherWindowSize = (-1, parentSashWindow.GetClientSize()[1] - window._sizeBeforeHidden[1])
+ if window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT):
+ self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT).SetDefaultSize(otherWindowSize)
+ elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT):
+ self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT).SetDefaultSize(otherWindowSize)
+ elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT):
+ self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT).SetDefaultSize(otherWindowSize)
+ elif window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT):
+ self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT).SetDefaultSize(otherWindowSize)
+
+ if not show:
+ if window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT) and not self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT).IsShown() \
+ or window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPRIGHT) and not self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMRIGHT).IsShown() \
+ or window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT) and not self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT).IsShown() \
+ or window == self.GetEmbeddedWindow(EMBEDDED_WINDOW_TOPLEFT) and not self.GetEmbeddedWindow(EMBEDDED_WINDOW_BOTTOMLEFT).IsShown():
+ parentSashWindow.Hide() # Hide the parent sashwindow if all of the children are hidden
+ parentSashWindow.Layout() # Force a refresh
+ parentSashWindow.Refresh()
+ parentSashWindow.SetSize((parentSashWindow.GetSize().width + 1, parentSashWindow.GetSize().height + 1))
+ self._LayoutFrame()
+
+
+ def HideEmbeddedWindow(self, window):
+ """
+ Hides the embedded window specified by the embedded window location constant.
+ """
+ self.ShowEmbeddedWindow(window, show=False)
+
+
+class DocTabbedChildFrame(wx.Panel):
+ """
+ The wxDocMDIChildFrame class provides a default frame for displaying
+ documents on separate windows. This class can only be used for MDI child
+ frames.
+
+ The class is part of the document/view framework supported by wxWindows,
+ and cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate
+ classes.
+ """
+
+
+ def __init__(self, doc, view, frame, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame"):
+ """
+ Constructor. Note that the event table must be rebuilt for the
+ frame since the EvtHandler is not virtual.
+ """
+ wx.Panel.__init__(self, frame.GetNotebook(), id)
+ self._childDocument = doc
+ self._childView = view
+ frame.AddNotebookPage(self, doc.GetPrintableName())
+ if view:
+ view.SetFrame(self)
+
+
+ def GetIcon(self):
+ """
+ Dummy method since the icon of tabbed frames are managed by the notebook.
+ """
+ return None
+
+
+ def SetIcon(self, icon):
+ """
+ Dummy method since the icon of tabbed frames are managed by the notebook.
+ """
+ pass
+
+
+ def Destroy(self):
+ """
+ Removes the current notebook page.
+ """
+ wx.GetApp().GetTopWindow().RemoveNotebookPage(self)
+
+
+ def SetFocus(self):
+ """
+ Activates the current notebook page.
+ """
+ wx.GetApp().GetTopWindow().ActivateNotebookPage(self)
+
+
+ def Activate(self): # Need this in case there are embedded sash windows and such, OnActivate is not getting called
+ """
+ Activates the current view.
+ """
+ # Called by Project Editor
+ if self._childView:
+ self._childView.Activate(True)
+
+
+ def GetTitle(self):
+ """
+ Returns the frame's title.
+ """
+ return wx.GetApp().GetTopWindow().GetNotebookPageTitle(self)
+
+
+ def SetTitle(self, title):
+ """
+ Sets the frame's title.
+ """
+ wx.GetApp().GetTopWindow().SetNotebookPageTitle(self, title)
+
+
+ def OnTitleIsModified(self):
+ """
+ Add/remove to the frame's title an indication that the document is dirty.
+ If the document is dirty, an '*' is appended to the title
+ """
+ title = self.GetTitle()
+ if title:
+ if self.GetDocument().IsModified():
+ if not title.endswith("*"):
+ title = title + "*"
+ self.SetTitle(title)
+ else:
+ if title.endswith("*"):
+ title = title[:-1]
+ self.SetTitle(title)
+
+
+ def ProcessEvent(event):
+ """
+ Processes an event, searching event tables and calling zero or more
+ suitable event handler function(s). Note that the ProcessEvent
+ method is called from the wxPython docview framework directly since
+ wxPython does not have a virtual ProcessEvent function.
+ """
+ if not self._childView or not self._childView.ProcessEvent(event):
+ if not isinstance(event, wx.CommandEvent) or not self.GetParent() or not self.GetParent().ProcessEvent(event):
+ return False
+ else:
+ return True
+ else:
+ return True
+
+
+ def GetDocument(self):
+ """
+ Returns the document associated with this frame.
+ """
+ return self._childDocument
+
+
+ def SetDocument(self, document):
+ """
+ Sets the document for this frame.
+ """
+ self._childDocument = document
+
+
+ def GetView(self):
+ """
+ Returns the view associated with this frame.
+ """
+ return self._childView
+
+
+ def SetView(self, view):
+ """
+ Sets the view for this frame.
+ """
+ self._childView = view
+
+
+class DocTabbedParentFrame(wx.Frame, DocFrameMixIn, DocMDIParentFrameMixIn):
+ """
+ The DocTabbedParentFrame class provides a default top-level frame for
+ applications using the document/view framework. This class can only be
+ used for MDI parent frames that use a tabbed interface.
+
+ It cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate
+ classes.
+ """
+
+
+ def __init__(self, docManager, frame, id, title, pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE, name = "DocTabbedParentFrame", embeddedWindows = 0, minSize=20):
+ """
+ Constructor. Note that the event table must be rebuilt for the
+ frame since the EvtHandler is not virtual.
+ """
+ pos, size = self._GetPosSizeFromConfig(pos, size)
+ wx.Frame.__init__(self, frame, id, title, pos, size, style, name)
+
+ # From docview.MDIParentFrame
+ self._docManager = docManager
+
+ wx.EVT_CLOSE(self, self.OnCloseWindow)
+
+ wx.EVT_MENU(self, wx.ID_EXIT, self.OnExit)
+ wx.EVT_MENU_RANGE(self, wx.ID_FILE1, wx.ID_FILE9, self.OnMRUFile)
+
+ wx.EVT_MENU(self, wx.ID_NEW, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_OPEN, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_CLOSE_ALL, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_CLOSE, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_REVERT, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_SAVE, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_SAVEAS, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_UNDO, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_REDO, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_PRINT, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_PRINT_SETUP, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_PREVIEW, self.ProcessEvent)
+ wx.EVT_MENU(self, wx.ID_ABOUT, self.OnAbout)
+
+ wx.EVT_UPDATE_UI(self, wx.ID_NEW, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_OPEN, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_CLOSE_ALL, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_CLOSE, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_REVERT, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_SAVE, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_SAVEAS, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_UNDO, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_REDO, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_PRINT, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_PRINT_SETUP, self.ProcessUpdateUIEvent)
+ wx.EVT_UPDATE_UI(self, wx.ID_PREVIEW, self.ProcessUpdateUIEvent)
+ # End From docview.MDIParentFrame
+
+ self.CreateNotebook()
+ self._InitFrame(embeddedWindows, minSize)
+
+
+ def _LayoutFrame(self):
+ """
+ Lays out the frame.
+ """
+ wx.LayoutAlgorithm().LayoutFrame(self, self._notebook)
+
+
+ def CreateNotebook(self):
+ """
+ Creates the notebook to use for the tabbed document interface.
+ """
+ if wx.Platform != "__WXMAC__":
+ self._notebook = wx.Notebook(self, wx.NewId())
+ else:
+ self._notebook = wx.Listbook(self, wx.NewId(), style=wx.LB_LEFT)
+ # self._notebook.SetSizer(wx.NotebookSizer(self._notebook))
+ if wx.Platform != "__WXMAC__":
+ wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self._notebook.GetId(), self.OnNotebookPageChanged)
+ else:
+ wx.EVT_LISTBOOK_PAGE_CHANGED(self, self._notebook.GetId(), self.OnNotebookPageChanged)
+ wx.EVT_RIGHT_DOWN(self._notebook, self.OnNotebookRightClick)
+ wx.EVT_MIDDLE_DOWN(self._notebook, self.OnNotebookMiddleClick)
+
+ # wxBug: wx.Listbook does not implement HitTest the same way wx.Notebook
+ # does, so for now don't fire MouseOver events.
+ if wx.Platform != "__WXMAC__":
+ wx.EVT_MOTION(self._notebook, self.OnNotebookMouseOver)
+
+ templates = wx.GetApp().GetDocumentManager().GetTemplates()
+ iconList = wx.ImageList(16, 16, initialCount = len(templates))
+ self._iconIndexLookup = []
+ for template in templates:
+ icon = template.GetIcon()
+ if icon:
+ if icon.GetHeight() != 16 or icon.GetWidth() != 16:
+ icon.SetHeight(16)
+ icon.SetWidth(16)
+ if wx.GetApp().GetDebug():
+ print "Warning: icon for '%s' isn't 16x16, not crossplatform" % template._docTypeName
+ iconIndex = iconList.AddIcon(icon)
+ self._iconIndexLookup.append((template, iconIndex))
+
+ icon = getBlankIcon()
+ if icon.GetHeight() != 16 or icon.GetWidth() != 16:
+ icon.SetHeight(16)
+ icon.SetWidth(16)
+ if wx.GetApp().GetDebug():
+ print "Warning: getBlankIcon isn't 16x16, not crossplatform"
+ self._blankIconIndex = iconList.AddIcon(icon)
+ self._notebook.AssignImageList(iconList)
+
+
+ def GetNotebook(self):
+ """
+ Returns the notebook used by the tabbed document interface.
+ """
+ return self._notebook
+
+
+ def GetActiveChild(self):
+ """
+ Returns the active notebook page, which to the framework is treated as
+ a document frame.
+ """
+ index = self._notebook.GetSelection()
+ if index == -1:
+ return None
+ return self._notebook.GetPage(index)
+
+
+ def OnNotebookPageChanged(self, event):
+ """
+ Activates a notebook page's view when it is selected.
+ """
+ index = self._notebook.GetSelection()
+ if index > -1:
+ self._notebook.GetPage(index).GetView().Activate()
+
+
+ def OnNotebookMouseOver(self, event):
+ # wxBug: On Windows XP the tooltips don't automatically disappear when you move the mouse and it is on a notebook tab, has nothing to do with this code!!!
+ index, type = self._notebook.HitTest(event.GetPosition())
+
+ if index > -1:
+ doc = self._notebook.GetPage(index).GetView().GetDocument()
+ # wxBug: Tooltips no longer appearing on tabs except on
+ # about a 2 pixel area between tab top and contents that will show tip.
+ self._notebook.GetParent().SetToolTip(wx.ToolTip(doc.GetFilename()))
+ else:
+ self._notebook.SetToolTip(wx.ToolTip(""))
+ event.Skip()
+
+
+ def OnNotebookMiddleClick(self, event):
+ """
+ Handles middle clicks for the notebook, closing the document whose tab was
+ clicked on.
+ """
+ index, type = self._notebook.HitTest(event.GetPosition())
+ if index > -1:
+ doc = self._notebook.GetPage(index).GetView().GetDocument()
+ if doc:
+ doc.DeleteAllViews()
+
+ def OnNotebookRightClick(self, event):
+ """
+ Handles right clicks for the notebook, enabling users to either close
+ a tab or select from the available documents if the user clicks on the
+ notebook's white space.
+ """
+ index, type = self._notebook.HitTest(event.GetPosition())
+ menu = wx.Menu()
+ x, y = event.GetX(), event.GetY()
+ if index > -1:
+ doc = self._notebook.GetPage(index).GetView().GetDocument()
+ id = wx.NewId()
+ menu.Append(id, _("Close"))
+ def OnRightMenuSelect(event):
+ doc.DeleteAllViews()
+ wx.EVT_MENU(self, id, OnRightMenuSelect)
+ if self._notebook.GetPageCount() > 1:
+ id = wx.NewId()
+ menu.Append(id, _("Close All but \"%s\"" % doc.GetPrintableName()))
+ def OnRightMenuSelect(event):
+ for i in range(self._notebook.GetPageCount()-1, -1, -1): # Go from len-1 to 0
+ if i != index:
+ doc = self._notebook.GetPage(i).GetView().GetDocument()
+ if not self.GetDocumentManager().CloseDocument(doc, False):
+ return
+ wx.EVT_MENU(self, id, OnRightMenuSelect)
+ menu.AppendSeparator()
+ tabsMenu = wx.Menu()
+ menu.AppendMenu(wx.NewId(), _("Select Tab"), tabsMenu)
+ else:
+ y = y - 25 # wxBug: It is offsetting click events in the blank notebook area
+ tabsMenu = menu
+
+ if self._notebook.GetPageCount() > 1:
+ selectIDs = {}
+ for i in range(0, self._notebook.GetPageCount()):
+ id = wx.NewId()
+ selectIDs[id] = i
+ tabsMenu.Append(id, self._notebook.GetPageText(i))
+ def OnRightMenuSelect(event):
+ self._notebook.SetSelection(selectIDs[event.GetId()])
+ wx.EVT_MENU(self, id, OnRightMenuSelect)
+
+ self._notebook.PopupMenu(menu, wx.Point(x, y))
+ menu.Destroy()
+
+
+ def AddNotebookPage(self, panel, title):
+ """
+ Adds a document page to the notebook.
+ """
+ self._notebook.AddPage(panel, title)
+ index = self._notebook.GetPageCount() - 1
+ self._notebook.SetSelection(index)
+
+ found = False # Now set the icon
+ template = panel.GetDocument().GetDocumentTemplate()
+ if template:
+ for t, iconIndex in self._iconIndexLookup:
+ if t is template:
+ self._notebook.SetPageImage(index, iconIndex)
+ found = True
+ break
+ if not found:
+ self._notebook.SetPageImage(index, self._blankIconIndex)
+
+ # wxBug: the wxListbook used on Mac needs its tabs list resized
+ # whenever a new tab is added, but the only way to do this is
+ # to resize the entire control
+ if wx.Platform == "__WXMAC__":
+ content_size = self._notebook.GetSize()
+ self._notebook.SetSize((content_size.x+2, -1))
+ self._notebook.SetSize((content_size.x, -1))
+
+ self._notebook.Layout()
+
+ windowMenuService = wx.GetApp().GetService(WindowMenuService)
+ if windowMenuService:
+ windowMenuService.BuildWindowMenu(wx.GetApp().GetTopWindow()) # build file menu list when we open a file
+
+
+ def RemoveNotebookPage(self, panel):
+ """
+ Removes a document page from the notebook.
+ """
+ index = self.GetNotebookPageIndex(panel)
+ if index > -1:
+ if self._notebook.GetPageCount() == 1 or index < 2:
+ pass
+ elif index >= 1:
+ self._notebook.SetSelection(index - 1)
+ elif index < self._notebook.GetPageCount():
+ self._notebook.SetSelection(index + 1)
+ self._notebook.DeletePage(index)
+ self._notebook.GetParent().SetToolTip(wx.ToolTip(""))
+
+ windowMenuService = wx.GetApp().GetService(WindowMenuService)
+ if windowMenuService:
+ windowMenuService.BuildWindowMenu(wx.GetApp().GetTopWindow()) # build file menu list when we open a file
+
+
+ def ActivateNotebookPage(self, panel):
+ """
+ Sets the notebook to the specified panel.
+ """
+ index = self.GetNotebookPageIndex(panel)
+ if index > -1:
+ self._notebook.SetFocus()
+ self._notebook.SetSelection(index)
+
+
+ def GetNotebookPageTitle(self, panel):
+ index = self.GetNotebookPageIndex(panel)
+ if index != -1:
+ return self._notebook.GetPageText(self.GetNotebookPageIndex(panel))
+ else:
+ return None
+
+
+ def SetNotebookPageTitle(self, panel, title):
+ self._notebook.SetPageText(self.GetNotebookPageIndex(panel), title)
+
+
+ def GetNotebookPageIndex(self, panel):
+ """
+ Returns the index of particular notebook panel.
+ """
+ index = -1
+ for i in range(self._notebook.GetPageCount()):
+ if self._notebook.GetPage(i) == panel:
+ index = i
+ break
+ return index
+
+
+ def ProcessEvent(self, event):
+ """
+ Processes an event, searching event tables and calling zero or more
+ suitable event handler function(s). Note that the ProcessEvent
+ method is called from the wxPython docview framework directly since
+ wxPython does not have a virtual ProcessEvent function.
+ """
+ if wx.GetApp().ProcessEventBeforeWindows(event):
+ return True
+ if self._docManager and self._docManager.ProcessEvent(event):
+ return True
+ return DocMDIParentFrameMixIn.ProcessEvent(self, event)
+
+
+ def ProcessUpdateUIEvent(self, event):
+ """
+ Processes a UI event, searching event tables and calling zero or more
+ suitable event handler function(s). Note that the ProcessEvent
+ method is called from the wxPython docview framework directly since
+ wxPython does not have a virtual ProcessEvent function.
+ """
+ if wx.GetApp().ProcessUpdateUIEventBeforeWindows(event):
+ return True
+ if self._docManager and self._docManager.ProcessUpdateUIEvent(event):
+ return True
+ return DocMDIParentFrameMixIn.ProcessUpdateUIEvent(self, event)
+
+
+ def OnExit(self, event):
+ """
+ Called when File/Exit is chosen and closes the window.
+ """
+ self.Close()
+
+
+ def OnMRUFile(self, event):
+ """
+ Opens the appropriate file when it is selected from the file history
+ menu.
+ """
+ n = event.GetId() - wx.ID_FILE1
+ filename = self._docManager.GetHistoryFile(n)
+ if filename:
+ self._docManager.CreateDocument(filename, wx.lib.docview.DOC_SILENT)
+ else:
+ self._docManager.RemoveFileFromHistory(n)
+ msgTitle = wx.GetApp().GetAppName()
+ if not msgTitle:
+ msgTitle = _("File Error")
+ 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),
+ msgTitle,
+ wx.OK | wx.ICON_EXCLAMATION,
+ self)
+
+
+ def OnSize(self, event):
+ """
+ Called when the frame is resized and lays out the client window.
+ """
+ # Needed in case there are splitpanels around the mdi frame
+ self._LayoutFrame()
+
+
+ def OnCloseWindow(self, event):
+ """
+ Called when the frame is closed. Remembers the frame size.
+ """
+ self.SaveEmbeddedWindowSizes()
+
+ # save and close services last
+ for service in wx.GetApp().GetServices():
+ if not service.OnCloseFrame(event):
+ return
+
+ # From docview.MDIParentFrame
+ if self._docManager.Clear(not event.CanVeto()):
+ self.Destroy()
+ else:
+ event.Veto()
+
+
+class DocMDIChildFrame(wx.MDIChildFrame):
+ """
+ The wxDocMDIChildFrame class provides a default frame for displaying
+ documents on separate windows. This class can only be used for MDI child
+ frames.
+
+ The class is part of the document/view framework supported by wxWindows,
+ and cooperates with the wxView, wxDocument, wxDocManager and wxDocTemplate
+ classes.
+ """
+
+
+ def __init__(self, doc, view, frame, id, title, pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, name="frame"):
+ """
+ Constructor. Note that the event table must be rebuilt for the
+ frame since the EvtHandler is not virtual.
+ """
+ wx.MDIChildFrame.__init__(self, frame, id, title, pos, size, style, name)
+ self._childDocument = doc
+ self._childView = view
+ if view:
+ view.SetFrame(self)
+ # self.Create(doc, view, frame, id, title, pos, size, style, name)
+ self._activeEvent = None
+ self._activated = 0
+ wx.EVT_ACTIVATE(self, self.OnActivate)
+ wx.EVT_CLOSE(self, self.OnCloseWindow)
+
+ 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
+ mdiChildren = filter(lambda x: isinstance(x, wx.MDIChildFrame), frame.GetChildren())
+ if len(mdiChildren) == 1:
+ self.Activate()
+
+
+## # Couldn't get this to work, but seems to work fine with single stage construction
+## def Create(self, doc, view, frame, id, title, pos, size, style, name):
+## self._childDocument = doc
+## self._childView = view
+## if wx.MDIChildFrame.Create(self, frame, id, title, pos, size, style, name):
+## if view:
+## view.SetFrame(self)
+## return True
+## return False
+
+
+
+ def Activate(self): # Need this in case there are embedded sash windows and such, OnActivate is not getting called
+ """
+ Activates the current view.
+ """
+ if self._childView:
+ self._childView.Activate(True)
+
+
+ def OnTitleIsModified(self):
+ """
+ Add/remove to the frame's title an indication that the document is dirty.
+ If the document is dirty, an '*' is appended to the title
+ """
+ title = self.GetTitle()
+ if title:
+ if self.GetDocument().IsModified():
+ if title.endswith("*"):
+ return
+ else:
+ title = title + "*"
+ self.SetTitle(title)
+ else:
+ if title.endswith("*"):
+ title = title[:-1]
+ self.SetTitle(title)
+ else:
+ return
+
+
+ def ProcessEvent(event):
+ """
+ Processes an event, searching event tables and calling zero or more
+ suitable event handler function(s). Note that the ProcessEvent
+ method is called from the wxPython docview framework directly since
+ wxPython does not have a virtual ProcessEvent function.
+ """
+ if self._activeEvent == event:
+ return False
+
+ self._activeEvent = event # Break recursion loops
+
+ if self._childView:
+ self._childView.Activate(True)
+
+ if not self._childView or not self._childView.ProcessEvent(event):
+ if not isinstance(event, wx.CommandEvent) or not self.GetParent() or not self.GetParent().ProcessEvent(event):
+ ret = False
+ else:
+ ret = True
+ else:
+ ret = True
+
+ self._activeEvent = None
+ return ret
+
+
+ def OnActivate(self, event):
+ """
+ Sets the currently active view to be the frame's view. You may need to
+ override (but still call) this function in order to set the keyboard
+ focus for your subwindow.
+ """
+ if self._activated != 0:
+ return True
+ self._activated += 1
+ wx.MDIChildFrame.Activate(self)
+ if event.GetActive() and self._childView:
+ self._childView.Activate(event.GetActive())
+ self._activated = 0
+
+
+ def OnCloseWindow(self, event):
+ """
+ Closes and deletes the current view and document.
+ """
+ if self._childView:
+ ans = False
+ if not event.CanVeto():
+ ans = True
+ else:
+ ans = self._childView.Close(deleteWindow = False)
+
+ if ans:
+ self._childView.Activate(False)
+ self._childView.Destroy()
+ self._childView = None
+ if self._childDocument:
+ self._childDocument.Destroy() # This isn't in the wxWindows codebase but the document needs to be disposed of somehow
+ self._childDocument = None
+ self.Destroy()
+ else:
+ event.Veto()
+ else:
+ event.Veto()
+
+
+ def GetDocument(self):
+ """
+ Returns the document associated with this frame.
+ """
+ return self._childDocument
+
+
+ def SetDocument(self, document):
+ """
+ Sets the document for this frame.
+ """
+ self._childDocument = document
+
+
+ def GetView(self):
+ """
+ Returns the view associated with this frame.
+ """
+ return self._childView
+
+
+ def SetView(self, view):
+ """
+ Sets the view for this frame.
+ """
+ self._childView = view
+
+
+class DocService(wx.EvtHandler):
+ """
+ An abstract class used to add reusable services to a docview application.
+ """
+
+
+ def __init__(self):
+ """Initializes the DocService."""
+ pass
+
+
+ def GetDocumentManager(self):
+ """Returns the DocManager for the docview application."""
+ return self._docManager
+
+
+ def SetDocumentManager(self, docManager):
+ """Sets the DocManager for the docview application."""
+ self._docManager = docManager
+
+
+ def InstallControls(self, frame, menuBar=None, toolBar=None, statusBar=None, document=None):
+ """Called to install controls into the menubar and toolbar of a SDI or MDI window. Override this method for a particular service."""
+ pass
+
+
+ def ProcessEventBeforeWindows(self, event):
+ """
+ Processes an event before the main window has a chance to process the window.
+ Override this method for a particular service.
+ """
+ return False
+
+
+ def ProcessUpdateUIEventBeforeWindows(self, event):
+ """
+ Processes a UI event before the main window has a chance to process the window.
+ Override this method for a particular service.
+ """
+ return False
+
+
+ def ProcessEvent(self, event):
+ """
+ Processes an event, searching event tables and calling zero or more
+ suitable event handler function(s). Note that the ProcessEvent
+ method is called from the wxPython docview framework directly since
+ wxPython does not have a virtual ProcessEvent function.
+ """
+ return False
+
+
+ def ProcessUpdateUIEvent(self, event):
+ """
+ Processes a UI event, searching event tables and calling zero or more
+ suitable event handler function(s). Note that the ProcessEvent
+ method is called from the wxPython docview framework directly since
+ wxPython does not have a virtual ProcessEvent function.
+ """
+ return False
+
+
+ def OnCloseFrame(self, event):
+ """
+ Called when the a docview frame is being closed. Override this method
+ so a service can either do cleanup or veto the frame being closed by
+ returning false.
+ """
+ return True
+
+
+ def OnExit(self):
+ """
+ Called when the the docview application is being closed. Override this method
+ so a service can either do cleanup or veto the frame being closed by
+ returning false.
+ """
+ pass
+
+
+ def GetMenuItemPos(self, menu, id):
+ """
+ Utility method used to find the position of a menu item so that services can
+ easily find where to insert a menu item in InstallControls.
+ """
+ menuItems = menu.GetMenuItems()
+ for i, menuItem in enumerate(menuItems):
+ if menuItem.GetId() == id:
+ return i
+ return i
+
+
+ def GetView(self):
+ """
+ Called by WindowMenuService to get views for services that don't
+ have dedicated documents such as the Outline Service.
+ """
+ return None
+
+
+class DocOptionsService(DocService):
+ """
+ A service that implements an options menu item and an options dialog with
+ notebook tabs. New tabs can be added by other services by calling the
+ "AddOptionsPanel" method.
+ """
+
+
+ def __init__(self, showGeneralOptions=True, supportedModes=wx.lib.docview.DOC_SDI & wx.lib.docview.DOC_MDI):
+ """
+ Initializes the options service with the option of suppressing the default
+ general options pane that is included with the options service by setting
+ showGeneralOptions to False. It allowModeChanges is set to False, the
+ default general options pane will allow users to change the document
+ interface mode between SDI and MDI modes.
+ """
+ DocService.__init__(self)
+ self.ClearOptionsPanels()
+ self._supportedModes = supportedModes
+ self._toolOptionsID = wx.ID_PREFERENCES
+ if showGeneralOptions:
+ self.AddOptionsPanel(GeneralOptionsPanel)
+
+
+ def InstallControls(self, frame, menuBar=None, toolBar=None, statusBar=None, document=None):
+ """
+ Installs a "Tools" menu with an "Options" menu item.
+ """
+ toolsMenuIndex = menuBar.FindMenu(_("&Tools"))
+ if toolsMenuIndex > -1:
+ toolsMenu = menuBar.GetMenu(toolsMenuIndex)
+ else:
+ toolsMenu = wx.Menu()
+ if toolsMenuIndex == -1:
+ formatMenuIndex = menuBar.FindMenu(_("&Format"))
+ menuBar.Insert(formatMenuIndex + 1, toolsMenu, _("&Tools"))
+ if toolsMenu:
+ if toolsMenu.GetMenuItemCount():
+ toolsMenu.AppendSeparator()
+ toolsMenu.Append(self._toolOptionsID, _("&Options..."), _("Sets options"))
+ wx.EVT_MENU(frame, self._toolOptionsID, frame.ProcessEvent)
+
+
+ def ProcessEvent(self, event):
+ """
+ Checks to see if the "Options" menu item has been selected.
+ """
+ id = event.GetId()
+ if id == self._toolOptionsID:
+ self.OnOptions(event)
+ return True
+ else:
+ return False
+
+
+ def GetSupportedModes(self):
+ """
+ Return the modes supported by the application. Use docview.DOC_SDI and
+ docview.DOC_MDI flags to check if SDI and/or MDI modes are supported.
+ """
+ return self._supportedModes
+
+
+ def SetSupportedModes(self, _supportedModessupportedModes):
+ """
+ Sets the modes supported by the application. Use docview.DOC_SDI and
+ docview.DOC_MDI flags to set if SDI and/or MDI modes are supported.
+ """
+ self._supportedModes = supportedModes
+
+
+ def ClearOptionsPanels(self):
+ """
+ Clears all of the options panels that have been added into the
+ options dialog.
+ """
+ self._optionsPanels = []
+
+
+ def AddOptionsPanel(self, optionsPanel):
+ """
+ Adds an options panel to the options dialog.
+ """
+ self._optionsPanels.append(optionsPanel)
+
+
+ def OnOptions(self, event):
+ """
+ Shows the options dialog, called when the "Options" menu item is selected.
+ """
+ if len(self._optionsPanels) == 0:
+ return
+ optionsDialog = OptionsDialog(wx.GetApp().GetTopWindow(), self._optionsPanels, self._docManager)
+ optionsDialog.CenterOnParent()
+ if optionsDialog.ShowModal() == wx.ID_OK:
+ optionsDialog.OnOK(optionsDialog) # wxBug: wxDialog should be calling this automatically but doesn't
+ optionsDialog.Destroy()
+
+
+class OptionsDialog(wx.Dialog):
+ """
+ A default options dialog used by the OptionsService that hosts a notebook
+ tab of options panels.
+ """
+
+
+ def __init__(self, parent, optionsPanelClasses, docManager):
+ """
+ Initializes the options dialog with a notebook page that contains new
+ instances of the passed optionsPanelClasses.
+ """
+ wx.Dialog.__init__(self, parent, -1, _("Options"))
+
+ self._optionsPanels = []
+ self._docManager = docManager
+
+ HALF_SPACE = 5
+ SPACE = 10