def initLayout(self): ModularStatusBar(self) if self.classprefs.show_popup_status: self.popup_status = PopupStatusBar(self) else: self.popup_status = None hsplit = wx.BoxSizer(wx.HORIZONTAL) self.SetAutoLayout(True) self.SetSizer(hsplit) self.spring = SpringTabs(self) # tell FrameManager to manage this frame self._mgr = aui.AuiManager() self._mgr.SetManagedWindow(self) self.tabs = FrameNotebook(self) self._mgr.AddPane(self.tabs, aui.AuiPaneInfo().Name("notebook").CenterPane()) self.sidebar_panes = [] # paneinfo can use the C++ style notation for setting flags because # each method of AuiPaneInfo returns itself paneinfo = aui.AuiPaneInfo().Name("SpringTabs").Caption( "SpringTabs").Left().Layer(10).CloseButton(False).CaptionVisible( False).LeftDockable(False).RightDockable(False) # Stock wxPython distributed with OS X 10.5 is version 2.8.4.0, which # apparently doesn't have the DockFixed method. So, I check for that # here before using it. if hasattr(paneinfo, 'DockFixed'): paneinfo.DockFixed() self._mgr.AddPane(self.spring, paneinfo)
def initLayout(self): ModularStatusBar(self) if self.classprefs.show_popup_status: self.popup_status = PopupStatusBar(self) else: self.popup_status = None hsplit = wx.BoxSizer(wx.HORIZONTAL) self.SetAutoLayout(True) self.SetSizer(hsplit) self.spring = SpringTabs(self) # tell FrameManager to manage this frame self._mgr = aui.AuiManager() self._mgr.SetManagedWindow(self) self.tabs = FrameNotebook(self) self._mgr.AddPane(self.tabs, aui.AuiPaneInfo().Name("notebook"). CenterPane()) self.sidebar_panes = [] # paneinfo can use the C++ style notation for setting flags because # each method of AuiPaneInfo returns itself paneinfo = aui.AuiPaneInfo().Name("SpringTabs").Caption("SpringTabs").Left().Layer(10).CloseButton(False).CaptionVisible(False).LeftDockable(False).RightDockable(False) # Stock wxPython distributed with OS X 10.5 is version 2.8.4.0, which # apparently doesn't have the DockFixed method. So, I check for that # here before using it. if hasattr(paneinfo, 'DockFixed'): paneinfo.DockFixed() self._mgr.AddPane(self.spring, paneinfo)
class BufferFrame(wx.Frame, ClassPrefs, debugmixin): frameid = 0 load_error_count = 0 size_timer = None preferences_tab = "General" preferences_label = "Windows" if wx.Platform == "__WXMAC__": icon = "icons/application_osx.png" else: icon = "icons/application.png" perspectives = {} default_classprefs = ( IntParam('width', 800, 'Width of the main frame in pixels'), IntParam('height', 600, 'Height of the main frame in pixels'), BoolParam( 'show_toolbar', True, 'Show the toolbar on all frames?\nNote: this is a global setting for all frames.' ), BoolParam( 'resize_becomes_default', True, 'Should the new size following a resize become the default size of all subsequently created frames?' ), BoolParam('show_popup_status', False, 'Use experimental popup status bar'), # FIXME: this attempt at fast resizing caused Freeze() mismatch # problems. It's not worth that much, so I'm disabling it for # now. # BoolParam('fast_resize', False, 'Speed up resize events by deferring window\nrepaints until the mouse stops moving'), ) default_menubar = { _("File"): 0, _("File/Export"): 850, # position within the parent menu for submenus _("Edit"): 0.001, _("View"): 0.003, _("View/Apply Settings"): -980, _("Tools"): 0.004, _("Transform"): 0.005, _("Project"): 1000.05, _("Documents"): 1000.1, _("Window"): 1000.2, _("&Help"): 1000.3, } def __init__(self, urls=[], id=-1, buffer=None): BufferFrame.frameid += 1 self.name = "peppy: Window #%d" % BufferFrame.frameid # flags to prevent multiple timestamp checks self.pending_timestamp_check = False self.currently_processing_timestamp = False # initialize superclass pos, size = self.initPositionAndSize() wx.Frame.__init__(self, None, id=-1, title=self.name, pos=pos, size=size, style=wx.DEFAULT_FRAME_STYLE | wx.CLIP_CHILDREN) self.initIcon() self.initLayout() self.initMenu() self.loadSidebars() self.initEventBindings() self.initLoad(buffer, urls) self.initRegisterWindow() self.Show() def initPositionAndSize(self): pos = wx.DefaultPosition size = (int(self.classprefs.width), int(self.classprefs.height)) return pos, size def initIcon(self): icon = wx.EmptyIcon() icon.CopyFromBitmap(getIconBitmap('icons/peppy.png')) self.SetIcon(icon) def initLayout(self): ModularStatusBar(self) if self.classprefs.show_popup_status: self.popup_status = PopupStatusBar(self) else: self.popup_status = None hsplit = wx.BoxSizer(wx.HORIZONTAL) self.SetAutoLayout(True) self.SetSizer(hsplit) self.spring = SpringTabs(self) # tell FrameManager to manage this frame self._mgr = aui.AuiManager() self._mgr.SetManagedWindow(self) self.tabs = FrameNotebook(self) self._mgr.AddPane(self.tabs, aui.AuiPaneInfo().Name("notebook").CenterPane()) self.sidebar_panes = [] # paneinfo can use the C++ style notation for setting flags because # each method of AuiPaneInfo returns itself paneinfo = aui.AuiPaneInfo().Name("SpringTabs").Caption( "SpringTabs").Left().Layer(10).CloseButton(False).CaptionVisible( False).LeftDockable(False).RightDockable(False) # Stock wxPython distributed with OS X 10.5 is version 2.8.4.0, which # apparently doesn't have the DockFixed method. So, I check for that # here before using it. if hasattr(paneinfo, 'DockFixed'): paneinfo.DockFixed() self._mgr.AddPane(self.spring, paneinfo) def initMenu(self): UserActionClassList.setDefaultMenuBarWeights(self.default_menubar) menubar = wx.MenuBar() if wx.Platform == '__WXMAC__': # turn off the automatic generation of the Window menu. # We generate one ourselves wx.MenuBar.SetAutoWindowMenu(False) # Replace the system Help menu with ours by creating this small # fake menu in order to register the help menu. Note that you # have to add something to the menubar on the mac (i.e. the # separator) in order for it to actually register with the Mac # menu system as being present. An empty Help menu is ignored as # far as SetMacHelpMenuTitleName is concerned. help = wx.Menu() help.AppendSeparator() menubar.Append(help, _("&Help")) wx.GetApp().SetMacHelpMenuTitleName(_("&Help")) self.SetMenuBar(menubar) self.show_toolbar = self.classprefs.show_toolbar self.root_accel = Null() def initEventBindings(self): self.dropTarget = FrameDropTarget(self) self.SetDropTarget(self.dropTarget) Publisher().subscribe(self.pluginsChanged, 'peppy.plugins.changed') wx.GetApp().SetTopWindow(self) self.bindEvents() def initLoad(self, buffer, urls): if buffer: self.newBuffer(buffer) else: self.loadList(urls) def initRegisterWindow(self): WindowList.append(self) def __str__(self): return "%s %s id=%s" % (self.__class__.__name__, self.name, hex(id(self))) def isOSXMinimalMenuFrame(self): return False def bindEvents(self): self.Bind(wx.EVT_CLOSE, self.OnClose) self.Bind(wx.EVT_ACTIVATE, self.OnRaise) self.Bind(wx.EVT_SIZE, self.OnSize) def unbindEvents(self): self.Unbind(wx.EVT_CLOSE) self.Unbind(wx.EVT_ACTIVATE) self.Unbind(wx.EVT_SIZE) def loadList(self, urls): if urls: wx.CallAfter(self.openList, urls) else: wx.CallAfter(self.titleBuffer) def openList(self, urls): self.tabs.holdChanges() for url in urls: #dprint("Opening %s" % url) self.open(url, force_new_tab=True) # If no pages have been open (due to errors), make sure that a title # buffer is displayed. if self.tabs.GetPageCount() == 0: self.titleBuffer() self.tabs.processChanges() def addPane(self, win, paneinfo): self._mgr.AddPane(win, paneinfo) def loadSidebars(self): sidebars = Sidebar.getClasses(self) for sidebarcls in sidebars: if sidebarcls.classprefs.springtab: self.spring.addTab(sidebarcls.caption, sidebarcls) else: self.createSidebar(sidebarcls) self.createSidebarList() def createSidebar(self, sidebarcls): """Create the sidebar and register it with the frame's AUI Manager.""" sidebar = sidebarcls(self) paneinfo = sidebar.getPaneInfo() self._mgr.AddPane(sidebar, paneinfo) sidebar.paneinfo = self._mgr.GetPane(sidebar) sidebar.activateSidebar() def createSidebarList(self): self.sidebar_panes = [] sidebars = self._mgr.GetAllPanes() for sidebar in sidebars: assert self.dprint( "name=%s caption=%s window=%s state=%s" % (sidebar.name, sidebar.caption, sidebar.window, sidebar.state)) if sidebar.name != "notebook": self.sidebar_panes.append(sidebar) self.sidebar_panes.sort(key=lambda s: s.caption) def closeSidebar(self): self.dprint("closing springtabs") self.spring.deleteTabs() for sidebar in self.sidebar_panes: self.dprint("closing sidebar %s" % sidebar.window) self._mgr.DetachPane(sidebar.window) sidebar.window.Destroy() sidebar.window = None sidebars = self._mgr.GetAllPanes() self.dprint("sidebars remaining: %s" % sidebars) self.sidebar_panes = None def processNormalIdleEvent(self): """Event processing for low priority idle functions. This event processor is called from the main application's idle event handler L{Peppy.OnIdle} with a minimum time between calls to this method. This is for expensive idle event functions or functions that don't need to be called that often to still provide good feedback to the user. """ if not self.IsActive(): self.dprint("Top window %s not active. No idle events." % self) return mode = self.getActiveMajorMode() if mode and mode.isReadyForIdleEvents(): # Refs #665: this call to forceToolbarUpdate causes the yield to # freeze until tabs get switched. Now this only happens when the # mode is ready for idle event processing self.root_accel.forceToolbarUpdate() # Timestamp checks are performed here for two reasons: 1) windows # reports activate events whenever a dialog is popped up, so # you get an unending stream of dialogs. 2) when trying to use # dialogs after changing tabs on linux, the mouse events seemed to # get eaten. The only workaround I could find was to put the call # to isModeChangedOnDisk here wrapped by a CallAfter. if self.pending_timestamp_check and not self.currently_processing_timestamp: self.currently_processing_timestamp = True wx.CallAfter(self.isModeChangedOnDisk) self.pending_timestamp_check = False #else: # dprint("mode %s not ready for idle events" % mode) def processPriorityIdleEvent(self): """Event processing that happens at every idle event This event processor is for high priority idle events that should be called as often as possible. Like L{processNormalIdleEvent}, this method is called from L{Peppy.OnIdle} but instead is called at every idle event. Compared to the calls in L{processNormalIdleEvent}, the functions called by this method should strive not to use much processing time because delays here will be much more noticeable to the user. """ if not self.IsActive(): self.dprint("Top window %s not active. No idle events." % self) return mode = self.getActiveMajorMode() if mode and mode.isReadyForIdleEvents(): #dprint("Idle for mode %s" % mode) mode.idleHandler() # Overrides of wx methods def OnRaise(self, evt): self.dprint("Focus! %s" % self.name) if evt.GetActive(): wx.GetApp().SetTopWindow(self) if not self.pending_timestamp_check and not self.currently_processing_timestamp: self.pending_timestamp_check = True else: if self.popup_status: self.popup_status.clear() evt.Skip() def OnSize(self, evt): # FIXME: this fast resizing was causing problems, so I've disabled it # with the embedded False if False and self.classprefs.fast_resize: if not self.tabs.IsFrozen(): dprint("not frozen. Freezing") self.tabs.Freeze() if not self.__class__.size_timer: self.__class__.size_timer = wx.PyTimer(self.OnSizeTimer) self.__class__.size_timer.Start(50, oneShot=True) else: self.rememberFrameSize() evt.Skip() def rememberFrameSize(self): if self.classprefs.resize_becomes_default: size = self.GetSize() self.classprefs.width = size.GetWidth() self.classprefs.height = size.GetHeight() def OnSizeTimer(self, evt=None): if self.tabs.IsFrozen(): dprint("frozen. Thawing") # FIXME: for some reason, IsFrozen returns True even when it's # not frozen. self.tabs.Thaw() def OnClose(self, evt=None): assert self.dprint(evt) if WindowList.canCloseWindow(self): self.closeWindow() WindowList.resetMacMinimalMenu() def Raise(self): wx.Frame.Raise(self) major = self.getActiveMajorMode() if major is not None: major.SetFocus() def SetStatusText(self, text, index=0, hold=False): """Overrides status bar with popup status. Instead of taking up screen real-estate with a status bar, the popup status displays a message for a small amount of time before disappearing. Depending on the value of index, a message can either remain on screen until the time expires, or can be overwritten by the next call to SetStatusText. Depending on the value of hold, a message can either remain on screen until the time expires, or can be overwritten by the next call to SetStatusText. @param text: the text (unicode) to display in the popup message @param index: 0 uses L{PopupStatusBar.showMessage} to display the text in the popup and will remain on screen till it expires; anything else uses L{PopupStatusBar.showStatusText} to display status info that gets overwritten with the next call. @param hold: if True, ignores expiration time and displays the status message until the next status message is displayed. """ if text: if self.popup_status: if index == 0 and not hold: self.popup_status.showMessage(_(text)) else: self.popup_status.showStatusText(_(text), hold) else: self.GetStatusBar().SetStatusText(_(text), index) # non-wx methods def showErrorDialog(self, msg, title="Error"): dlg = wx.MessageDialog(self, msg, title, wx.OK | wx.ICON_ERROR) retval = dlg.ShowModal() return retval def showWarningDialog(self, msg, title="Warning"): dlg = wx.MessageDialog(self, msg, title, wx.OK | wx.ICON_WARNING) retval = dlg.ShowModal() return retval def showQuestionDialog(self, msg, title="Question"): dlg = wx.MessageDialog(self, msg, title, wx.YES_NO | wx.ICON_QUESTION) retval = dlg.ShowModal() return retval def clearMenumap(self): self.root_accel.cleanupAndDelete() def setMenumap(self, mode): self.clearMenumap() self.root_accel = UserAccelerators(self, mode) #storeWeakref('menumap', self.menumap) self.root_accel.updateActions(self.show_toolbar) self._mgr.Update() def updateMenumap(self): self.root_accel.forceToolbarUpdate() def getActiveMajorMode(self): if self.tabs is not None: wrapper = self.tabs.getCurrent() if wrapper: major = self.tabs.getCurrent().editwin return major return None def getAllMajorModes(self): modes = self.tabs.getAll() return modes def isOpen(self): major = self.getActiveMajorMode() #assert self.dprint("major=%s isOpen=%s" % (str(major),str(major!=None))) return major is not None def isTopWindow(self): return wx.GetApp().GetTopWindow() == self def closeWindow(self): self.unbindEvents() self.clearMenumap() self.closeSidebar() WindowList.remove(self) self.Hide() self.tabs.closeAllTabs() self._mgr.DetachPane(self.tabs) self.tabs = None self.Destroy() @classmethod def closeAllWindows(cls): frames = WindowList.getFrames() for frame in frames: frame.closeWindow() def closeBuffer(self): major = self.getActiveMajorMode() if major: buffer = major.buffer if buffer.permanent: self.tabs.closeWrapper(major) else: if buffer.modified: dlg = wx.MessageDialog( self, "%s\n\nhas unsaved changes.\n\nClose anyway?" % buffer.displayname, "Unsaved Changes", wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) retval = dlg.ShowModal() dlg.Destroy() else: retval = wx.ID_YES if retval == wx.ID_YES: if buffer.numViewers() > 1: dlg = wx.MessageDialog( self, u"Multiple views of:\n\n%s\n\nexist. Really remove buffer?" % buffer.url, "Remove All Views?", wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) retval = dlg.ShowModal() dlg.Destroy() else: retval = wx.ID_YES if retval == wx.ID_YES: buffer.removeAllViewsAndDelete() def setTitle(self): self.SetTitle(self.getTitle()) def getTitle(self): major = self.getActiveMajorMode() if major: return u"peppy: %s (%s)" % (major.getTabName(), unicode(major.buffer.url)) return self.name def showModified(self, major): current = self.getActiveMajorMode() if current: self.setTitle() self.tabs.updateWrapperTitle(major) def titleBuffer(self): self.open(wx.GetApp().classprefs.title_page) def isTitleBufferOnly(self): if len(self.getAllMajorModes()) > 1: return False mode = self.getActiveMajorMode() url = vfs.normalize(wx.GetApp().classprefs.title_page) dprint(u"%s == %s => %s" % (url, mode.buffer.url, mode.buffer.url == url)) if mode.buffer.url == url: return True return False def setBuffer(self, buffer, wrapper=None, use_current=None, options=None): if wrapper is None: if use_current: wrapper = self.tabs.getCurrent() else: # this gets a default view for the selected buffer wrapper = self.tabs.getDocumentWrapper() mode = self.tabs.newMode(buffer, wrapper=wrapper) assert self.dprint("set buffer to new view %s" % mode) if not mode.isErrorMode(): mode.showInitialPosition(buffer.raw_url, options) mode.setReadyForIdleEvents() def newBuffer(self, buffer): # proxy it up to tabs self.tabs.newBuffer(buffer.url, buffer) def changeMajorMode(self, requested): """Change the currently active major mode to the requested mode This changes the view of the current buffer to the new mode, but doesn't change any of the data in the buffer. """ mode = self.getActiveMajorMode() cursor_data = mode.getViewPositionData() newmode = self.tabs.newMode(mode.buffer, requested, mode) if not newmode.isErrorMode(): newmode.setViewPositionData(cursor_data) newmode.setReadyForIdleEvents() def makeTabActive(self, url, options=None): """Make the tab current that corresponds to the url. If the url isn't found, nothing happens. @return: True if URL was found, False if not. """ normalized = vfs.normalize(url) self.dprint("url=%s normalized=%s" % (url, normalized)) mode = self.tabs.moveSelectionToURL(normalized) if mode: mode.showInitialPosition(normalized) if options: mode.setViewPositionData(options) return mode is not None def findTabOrOpen(self, url, options=None): """Find a tab that contains this URL, otherwise open a new tab""" if not self.makeTabActive(url, options=options): self.open(url, options=options) def open(self, *args, **kwargs): """Open a new tab to edit the given URL. Driver function that uses L{FileOpener} to open URLs """ try: opener = FileOpener(self, *args, **kwargs) except FileOpenerExceptionHandled: pass except vfs.AuthenticationCancelled: pass except vfs.NetworkError, e: self.SetStatusText(e)
class BufferFrame(wx.Frame, ClassPrefs, debugmixin): frameid=0 load_error_count = 0 size_timer = None preferences_tab = "General" preferences_label = "Windows" if wx.Platform == "__WXMAC__": icon = "icons/application_osx.png" else: icon = "icons/application.png" perspectives={} default_classprefs = ( IntParam('width', 800, 'Width of the main frame in pixels'), IntParam('height', 600, 'Height of the main frame in pixels'), BoolParam('show_toolbar', True, 'Show the toolbar on all frames?\nNote: this is a global setting for all frames.'), BoolParam('resize_becomes_default', True, 'Should the new size following a resize become the default size of all subsequently created frames?'), BoolParam('show_popup_status', False, 'Use experimental popup status bar'), # FIXME: this attempt at fast resizing caused Freeze() mismatch # problems. It's not worth that much, so I'm disabling it for # now. # BoolParam('fast_resize', False, 'Speed up resize events by deferring window\nrepaints until the mouse stops moving'), ) default_menubar = { _("File"): 0, _("File/Export"): 850, # position within the parent menu for submenus _("Edit"): 0.001, _("View"): 0.003, _("View/Apply Settings"): -980, _("Tools"): 0.004, _("Transform"): 0.005, _("Project"): 1000.05, _("Documents"): 1000.1, _("Window"): 1000.2, _("&Help"): 1000.3, } def __init__(self, urls=[], id=-1, buffer=None): BufferFrame.frameid+=1 self.name="peppy: Window #%d" % BufferFrame.frameid # flags to prevent multiple timestamp checks self.pending_timestamp_check = False self.currently_processing_timestamp = False # initialize superclass pos, size = self.initPositionAndSize() wx.Frame.__init__(self, None, id=-1, title=self.name, pos=pos, size=size, style=wx.DEFAULT_FRAME_STYLE|wx.CLIP_CHILDREN) self.initIcon() self.initLayout() self.initMenu() self.loadSidebars() self.initEventBindings() self.initLoad(buffer, urls) self.initRegisterWindow() self.Show() def initPositionAndSize(self): pos = wx.DefaultPosition size = (int(self.classprefs.width), int(self.classprefs.height)) return pos, size def initIcon(self): icon = wx.EmptyIcon() icon.CopyFromBitmap(getIconBitmap('icons/peppy.png')) self.SetIcon(icon) def initLayout(self): ModularStatusBar(self) if self.classprefs.show_popup_status: self.popup_status = PopupStatusBar(self) else: self.popup_status = None hsplit = wx.BoxSizer(wx.HORIZONTAL) self.SetAutoLayout(True) self.SetSizer(hsplit) self.spring = SpringTabs(self) # tell FrameManager to manage this frame self._mgr = aui.AuiManager() self._mgr.SetManagedWindow(self) self.tabs = FrameNotebook(self) self._mgr.AddPane(self.tabs, aui.AuiPaneInfo().Name("notebook"). CenterPane()) self.sidebar_panes = [] # paneinfo can use the C++ style notation for setting flags because # each method of AuiPaneInfo returns itself paneinfo = aui.AuiPaneInfo().Name("SpringTabs").Caption("SpringTabs").Left().Layer(10).CloseButton(False).CaptionVisible(False).LeftDockable(False).RightDockable(False) # Stock wxPython distributed with OS X 10.5 is version 2.8.4.0, which # apparently doesn't have the DockFixed method. So, I check for that # here before using it. if hasattr(paneinfo, 'DockFixed'): paneinfo.DockFixed() self._mgr.AddPane(self.spring, paneinfo) def initMenu(self): UserActionClassList.setDefaultMenuBarWeights(self.default_menubar) menubar = wx.MenuBar() if wx.Platform == '__WXMAC__': # turn off the automatic generation of the Window menu. # We generate one ourselves wx.MenuBar.SetAutoWindowMenu(False) # Replace the system Help menu with ours by creating this small # fake menu in order to register the help menu. Note that you # have to add something to the menubar on the mac (i.e. the # separator) in order for it to actually register with the Mac # menu system as being present. An empty Help menu is ignored as # far as SetMacHelpMenuTitleName is concerned. help = wx.Menu() help.AppendSeparator() menubar.Append(help, _("&Help")) wx.GetApp().SetMacHelpMenuTitleName(_("&Help")) self.SetMenuBar(menubar) self.show_toolbar = self.classprefs.show_toolbar self.root_accel = Null() def initEventBindings(self): self.dropTarget=FrameDropTarget(self) self.SetDropTarget(self.dropTarget) Publisher().subscribe(self.pluginsChanged, 'peppy.plugins.changed') wx.GetApp().SetTopWindow(self) self.bindEvents() def initLoad(self, buffer, urls): if buffer: self.newBuffer(buffer) else: self.loadList(urls) def initRegisterWindow(self): WindowList.append(self) def __str__(self): return "%s %s id=%s" % (self.__class__.__name__, self.name, hex(id(self))) def isOSXMinimalMenuFrame(self): return False def bindEvents(self): self.Bind(wx.EVT_CLOSE,self.OnClose) self.Bind(wx.EVT_ACTIVATE, self.OnRaise) self.Bind(wx.EVT_SIZE, self.OnSize) def unbindEvents(self): self.Unbind(wx.EVT_CLOSE) self.Unbind(wx.EVT_ACTIVATE) self.Unbind(wx.EVT_SIZE) def loadList(self, urls): if urls: wx.CallAfter(self.openList, urls) else: wx.CallAfter(self.titleBuffer) def openList(self, urls): self.tabs.holdChanges() for url in urls: #dprint("Opening %s" % url) self.open(url, force_new_tab=True) # If no pages have been open (due to errors), make sure that a title # buffer is displayed. if self.tabs.GetPageCount() == 0: self.titleBuffer() self.tabs.processChanges() def addPane(self, win, paneinfo): self._mgr.AddPane(win, paneinfo) def loadSidebars(self): sidebars = Sidebar.getClasses(self) for sidebarcls in sidebars: if sidebarcls.classprefs.springtab: self.spring.addTab(sidebarcls.caption, sidebarcls) else: self.createSidebar(sidebarcls) self.createSidebarList() def createSidebar(self, sidebarcls): """Create the sidebar and register it with the frame's AUI Manager.""" sidebar = sidebarcls(self) paneinfo = sidebar.getPaneInfo() self._mgr.AddPane(sidebar, paneinfo) sidebar.paneinfo = self._mgr.GetPane(sidebar) sidebar.activateSidebar() def createSidebarList(self): self.sidebar_panes = [] sidebars = self._mgr.GetAllPanes() for sidebar in sidebars: assert self.dprint("name=%s caption=%s window=%s state=%s" % (sidebar.name, sidebar.caption, sidebar.window, sidebar.state)) if sidebar.name != "notebook": self.sidebar_panes.append(sidebar) self.sidebar_panes.sort(key=lambda s:s.caption) def closeSidebar(self): self.dprint("closing springtabs") self.spring.deleteTabs() for sidebar in self.sidebar_panes: self.dprint("closing sidebar %s" % sidebar.window) self._mgr.DetachPane(sidebar.window) sidebar.window.Destroy() sidebar.window = None sidebars = self._mgr.GetAllPanes() self.dprint("sidebars remaining: %s" % sidebars) self.sidebar_panes = None def processNormalIdleEvent(self): """Event processing for low priority idle functions. This event processor is called from the main application's idle event handler L{Peppy.OnIdle} with a minimum time between calls to this method. This is for expensive idle event functions or functions that don't need to be called that often to still provide good feedback to the user. """ if not self.IsActive(): self.dprint("Top window %s not active. No idle events." % self) return mode = self.getActiveMajorMode() if mode and mode.isReadyForIdleEvents(): # Refs #665: this call to forceToolbarUpdate causes the yield to # freeze until tabs get switched. Now this only happens when the # mode is ready for idle event processing self.root_accel.forceToolbarUpdate() # Timestamp checks are performed here for two reasons: 1) windows # reports activate events whenever a dialog is popped up, so # you get an unending stream of dialogs. 2) when trying to use # dialogs after changing tabs on linux, the mouse events seemed to # get eaten. The only workaround I could find was to put the call # to isModeChangedOnDisk here wrapped by a CallAfter. if self.pending_timestamp_check and not self.currently_processing_timestamp: self.currently_processing_timestamp = True wx.CallAfter(self.isModeChangedOnDisk) self.pending_timestamp_check = False #else: # dprint("mode %s not ready for idle events" % mode) def processPriorityIdleEvent(self): """Event processing that happens at every idle event This event processor is for high priority idle events that should be called as often as possible. Like L{processNormalIdleEvent}, this method is called from L{Peppy.OnIdle} but instead is called at every idle event. Compared to the calls in L{processNormalIdleEvent}, the functions called by this method should strive not to use much processing time because delays here will be much more noticeable to the user. """ if not self.IsActive(): self.dprint("Top window %s not active. No idle events." % self) return mode = self.getActiveMajorMode() if mode and mode.isReadyForIdleEvents(): #dprint("Idle for mode %s" % mode) mode.idleHandler() # Overrides of wx methods def OnRaise(self, evt): self.dprint("Focus! %s" % self.name) if evt.GetActive(): wx.GetApp().SetTopWindow(self) if not self.pending_timestamp_check and not self.currently_processing_timestamp: self.pending_timestamp_check = True else: if self.popup_status: self.popup_status.clear() evt.Skip() def OnSize(self, evt): # FIXME: this fast resizing was causing problems, so I've disabled it # with the embedded False if False and self.classprefs.fast_resize: if not self.tabs.IsFrozen(): dprint("not frozen. Freezing") self.tabs.Freeze() if not self.__class__.size_timer: self.__class__.size_timer = wx.PyTimer(self.OnSizeTimer) self.__class__.size_timer.Start(50, oneShot=True) else: self.rememberFrameSize() evt.Skip() def rememberFrameSize(self): if self.classprefs.resize_becomes_default: size = self.GetSize() self.classprefs.width = size.GetWidth() self.classprefs.height = size.GetHeight() def OnSizeTimer(self, evt=None): if self.tabs.IsFrozen(): dprint("frozen. Thawing") # FIXME: for some reason, IsFrozen returns True even when it's # not frozen. self.tabs.Thaw() def OnClose(self, evt=None): assert self.dprint(evt) if WindowList.canCloseWindow(self): self.closeWindow() def Raise(self): wx.Frame.Raise(self) major=self.getActiveMajorMode() if major is not None: major.SetFocus() def SetStatusText(self, text, index=0, hold=False): """Overrides status bar with popup status. Instead of taking up screen real-estate with a status bar, the popup status displays a message for a small amount of time before disappearing. Depending on the value of index, a message can either remain on screen until the time expires, or can be overwritten by the next call to SetStatusText. Depending on the value of hold, a message can either remain on screen until the time expires, or can be overwritten by the next call to SetStatusText. @param text: the text (unicode) to display in the popup message @param index: 0 uses L{PopupStatusBar.showMessage} to display the text in the popup and will remain on screen till it expires; anything else uses L{PopupStatusBar.showStatusText} to display status info that gets overwritten with the next call. @param hold: if True, ignores expiration time and displays the status message until the next status message is displayed. """ if text: if self.popup_status: if index == 0 and not hold: self.popup_status.showMessage(_(text)) else: self.popup_status.showStatusText(_(text), hold) else: self.GetStatusBar().SetStatusText(_(text), index) # non-wx methods def showErrorDialog(self, msg, title="Error"): dlg = wx.MessageDialog(self, msg, title, wx.OK | wx.ICON_ERROR ) retval = dlg.ShowModal() return retval def showWarningDialog(self, msg, title="Warning"): dlg = wx.MessageDialog(self, msg, title, wx.OK | wx.ICON_WARNING ) retval = dlg.ShowModal() return retval def showQuestionDialog(self, msg, title="Question"): dlg = wx.MessageDialog(self, msg, title, wx.YES_NO | wx.ICON_QUESTION ) retval = dlg.ShowModal() return retval def clearMenumap(self): self.root_accel.cleanupAndDelete() def setMenumap(self, mode): self.clearMenumap() self.root_accel = UserAccelerators(self, mode) #storeWeakref('menumap', self.menumap) self.root_accel.updateActions(self.show_toolbar) self._mgr.Update() def updateMenumap(self): self.root_accel.forceToolbarUpdate() def getActiveMajorMode(self): if self.tabs is not None: wrapper = self.tabs.getCurrent() if wrapper: major=self.tabs.getCurrent().editwin return major return None def getAllMajorModes(self): modes = self.tabs.getAll() return modes def isOpen(self): major=self.getActiveMajorMode() #assert self.dprint("major=%s isOpen=%s" % (str(major),str(major!=None))) return major is not None def isTopWindow(self): return wx.GetApp().GetTopWindow()==self def closeWindow(self): self.unbindEvents() self.clearMenumap() self.closeSidebar() WindowList.remove(self) self.Hide() self.tabs.closeAllTabs() self._mgr.DetachPane(self.tabs) self.tabs = None self.Destroy() @classmethod def closeAllWindows(cls): frames = WindowList.getFrames() for frame in frames: frame.closeWindow() def closeBuffer(self): major=self.getActiveMajorMode() if major: buffer=major.buffer if buffer.permanent: self.tabs.closeWrapper(major) else: if buffer.modified: dlg = wx.MessageDialog(self, "%s\n\nhas unsaved changes.\n\nClose anyway?" % buffer.displayname, "Unsaved Changes", wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION ) retval=dlg.ShowModal() dlg.Destroy() else: retval=wx.ID_YES if retval==wx.ID_YES: if buffer.numViewers() > 1: dlg = wx.MessageDialog(self, u"Multiple views of:\n\n%s\n\nexist. Really remove buffer?" % buffer.url, "Remove All Views?", wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION ) retval=dlg.ShowModal() dlg.Destroy() else: retval=wx.ID_YES if retval==wx.ID_YES: buffer.removeAllViewsAndDelete() def setTitle(self): self.SetTitle(self.getTitle()) def getTitle(self): major = self.getActiveMajorMode() if major: return u"peppy: %s (%s)" % (major.getTabName(), unicode(major.buffer.url)) return self.name def showModified(self, major): current=self.getActiveMajorMode() if current: self.setTitle() self.tabs.updateWrapperTitle(major) def titleBuffer(self): self.open(wx.GetApp().classprefs.title_page) def isTitleBufferOnly(self): if len(self.getAllMajorModes()) > 1: return False mode = self.getActiveMajorMode() url = vfs.normalize(wx.GetApp().classprefs.title_page) dprint(u"%s == %s => %s" % (url, mode.buffer.url, mode.buffer.url == url)) if mode.buffer.url == url: return True return False def setBuffer(self, buffer, wrapper=None, use_current=None, options=None): if wrapper is None: if use_current: wrapper = self.tabs.getCurrent() else: # this gets a default view for the selected buffer wrapper = self.tabs.getDocumentWrapper() mode = self.tabs.newMode(buffer, wrapper=wrapper) assert self.dprint("set buffer to new view %s" % mode) if not mode.isErrorMode(): mode.showInitialPosition(buffer.raw_url, options) mode.setReadyForIdleEvents() def newBuffer(self, buffer): # proxy it up to tabs self.tabs.newBuffer(buffer.url, buffer) def changeMajorMode(self, requested): """Change the currently active major mode to the requested mode This changes the view of the current buffer to the new mode, but doesn't change any of the data in the buffer. """ mode = self.getActiveMajorMode() cursor_data = mode.getViewPositionData() newmode = self.tabs.newMode(mode.buffer, requested, mode) if not newmode.isErrorMode(): newmode.setViewPositionData(cursor_data) newmode.setReadyForIdleEvents() def makeTabActive(self, url, options=None): """Make the tab current that corresponds to the url. If the url isn't found, nothing happens. @return: True if URL was found, False if not. """ normalized = vfs.normalize(url) self.dprint("url=%s normalized=%s" % (url, normalized)) mode = self.tabs.moveSelectionToURL(normalized) if mode: mode.showInitialPosition(normalized) if options: mode.setViewPositionData(options) return mode is not None def findTabOrOpen(self, url, options=None): """Find a tab that contains this URL, otherwise open a new tab""" if not self.makeTabActive(url, options=options): self.open(url, options=options) def open(self, *args, **kwargs): """Open a new tab to edit the given URL. Driver function that uses L{FileOpener} to open URLs """ try: opener = FileOpener(self, *args, **kwargs) except FileOpenerExceptionHandled: pass except vfs.AuthenticationCancelled: pass except vfs.NetworkError, e: self.SetStatusText(e)