############################################################################### # Name: ed_main.py # # Purpose: Editra's Main Window # # Author: Cody Precord # # Copyright: (c) 2008 Cody Precord # # License: wxWindows License # ############################################################################### """@package Editra.src.ed_main This module provides the L{MainWindow} class for Editra. The MainWindow is main Ui component of the editor that contains all the other components. @summary: MainWindow Component """ __author__ = "Cody Precord " __svnid__ = "$Id: ed_main.py 72388 2012-08-28 16:06:31Z CJP $" __revision__ = "$Revision: 72388 $" #--------------------------------------------------------------------------# # Dependencies import os import sys import time import wx # Editra Libraries from ed_glob import * import util import profiler import ed_toolbar import ed_mpane import ed_event import ed_msg import ed_menu import ed_print import ed_shelf import ed_statbar import ed_mdlg import prefdlg import syntax.syntax as syntax import generator import plugin import ed_fmgr import perspective as viewmgr import ed_session import iface import ebmlib import eclib # Function Aliases _ = wx.GetTranslation _PGET = profiler.Profile_Get _PSET = profiler.Profile_Set #--------------------------------------------------------------------------# class MainWindow(wx.Frame, viewmgr.PerspectiveManager): """Editras Main Window""" # Clipboard ring is limited to 25 entries CLIPBOARD = util.EdClipboard(25) PRINTER = None def __init__(self, parent, id_, wsize, title): """Initialize the Frame and Event Handlers. @param wsize: Windows initial size @param title: Windows Title """ wx.Frame.__init__(self, parent, id_, title, size=wsize, style=wx.DEFAULT_FRAME_STYLE) viewmgr.PerspectiveManager.__init__(self, CONFIG['CACHE_DIR']) # Setup app icon and title util.SetWindowIcon(self) # Attributes self._loaded = False self._initialized = False # for GTK OnActivate HACK self._mlock = ebmlib.CallLock() self._last_save = u'' self.LOG = wx.GetApp().GetLog() self._exiting = False self._handlers = dict(menu=list(), ui=list()) #---- Setup File History ----# self.filehistory = ebmlib.EFileHistory(_PGET('FHIST_LVL', 'int', 9)) #---- Status bar on bottom of window ----# self.SetStatusBar(ed_statbar.EdStatBar(self)) self.GetStatusBar().Show(_PGET('STATBAR', default=True)) #---- End Statusbar Setup ----# #---- Notebook that contains the editing buffers ----# self._mpane = ed_mpane.MainPanel(self) self.nb = self._mpane.GetWindow() self.PanelMgr.AddPane(self._mpane, ed_fmgr.EdPaneInfo(). \ Name("EditPane").Center().Layer(1).Dockable(False). \ CloseButton(False).MaximizeButton(False). \ CaptionVisible(False)) #---- Command Bar ----# self._mpane.HideCommandBar() #---- Pane Navigator ----# self._paneNavi = None # Printer Setup if MainWindow.PRINTER is None: MainWindow.PRINTER = ed_print.EdPrinter(self) #---- Setup Toolbar ----# self.SetupToolBar() #---- End Toolbar Setup ----# #---- Menus ----# menbar = ed_menu.EdMenuBar() # Todo this should not be hard coded menbar.GetMenuByName("view").InsertMenu(5, ID_PERSPECTIVES, _("Perspectives"), self.GetPerspectiveControls()) ## Setup additional menu items self.filehistory.UseMenu(menbar.GetMenuByName("filehistory")) # On mac, do this to make help menu appear in correct location # Note it must be done before setting the menu bar and after the # menus have been created. if wx.Platform == '__WXMAC__': wx.GetApp().SetMacHelpMenuTitleName(_("&Help")) #---- Menu Bar ----# self.SetMenuBar(menbar) #---- Actions to take on menu events ----# # Collect Menu Event handler pairs self._handlers['menu'].extend([# File Menu (ID_NEW, self.OnNew), (ID_OPEN, self.OnOpen), (ID_CLOSE, self.OnClosePage), (ID_CLOSEALL, self.OnClosePage), (ID_SAVE, self.OnSave), (ID_SAVEAS, self.OnSaveAs), (ID_SAVEALL, self.OnSave), (ID_REVERT_FILE, self.DispatchToControl), (ID_RELOAD_ENC, self.OnReloadWithEnc), (ID_SAVE_PROFILE, self.OnSaveProfile), (ID_LOAD_PROFILE, self.OnLoadProfile), (ID_SAVE_SESSION, self.OnSaveSession), (ID_LOAD_SESSION, self.OnLoadSession), (ID_EXIT, wx.GetApp().OnExit), (ID_PRINT, self.OnPrint), (ID_PRINT_PRE, self.OnPrint), (ID_PRINT_SU, self.OnPrint), # Edit Menu (ID_PASTE_AFTER, self.DispatchToControl), (ID_CYCLE_CLIPBOARD, self.DispatchToControl), (ID_COLUMN_MODE, self.DispatchToControl), (ID_TOGGLE_FOLD, self.DispatchToControl), (ID_TOGGLE_ALL_FOLDS, self.DispatchToControl), (ID_SHOW_AUTOCOMP, self.DispatchToControl), (ID_SHOW_CALLTIP, self.DispatchToControl), (ID_QUICK_FIND, self.OnCommandBar), (ID_PREF, OnPreferences), # View Menu (ID_GOTO_LINE, self.OnCommandBar), (ID_GOTO_MBRACE, self.DispatchToControl), (ID_SHOW_SB, self.OnShowStatusBar), (ID_VIEW_TOOL, self.OnViewTb), (ID_PANELIST, self.OnPaneList), (ID_MAXIMIZE_EDITOR, self.OnMaximizeEditor), # Format Menu (ID_FONT, self.OnFont), # Settings menu (ID_LEXER_CUSTOM, self.OnCustomizeLangMenu), # Tool Menu (ID_COMMAND, self.OnCommandBar), (ID_STYLE_EDIT, self.OnStyleEdit), (ID_PLUGMGR, self.OnPluginMgr), (ID_SESSION_BAR, self.OnCommandBar), # Help Menu (ID_ABOUT, OnAbout), (ID_HOMEPAGE, self.OnHelp), (ID_DOCUMENTATION, self.OnHelp), (ID_TRANSLATE, self.OnHelp), (ID_CONTACT, self.OnHelp), (ID_BUG_TRACKER, self.OnHelp)]) self._handlers['menu'].extend([(l_id, self.DispatchToControl) for l_id in syntax.SYNTAX_IDS]) # Extra menu handlers (need to work these into above system yet) self.Bind(wx.EVT_MENU, self.DispatchToControl) self.Bind(wx.EVT_MENU, self.OnGenerate) self.Bind(wx.EVT_MENU_RANGE, self.OnFileHistory, id=wx.ID_FILE1, id2=wx.ID_FILE9) # Update UI Handlers self._handlers['ui'].extend([# File Menu (ID_REVERT_FILE, self.OnUpdateFileUI), (ID_RELOAD_ENC, self.OnUpdateFileUI), # Edit Menu (ID_COPY, self.OnUpdateClipboardUI), (ID_CUT, self.OnUpdateClipboardUI), (ID_PASTE, self.OnUpdateClipboardUI), (ID_PASTE_AFTER, self.OnUpdateClipboardUI), (ID_CYCLE_CLIPBOARD, self.OnUpdateClipboardUI), (ID_UNDO, self.OnUpdateClipboardUI), (ID_REDO, self.OnUpdateClipboardUI), (ID_COLUMN_MODE, self.OnUpdateClipboardUI), # Format Menu (ID_INDENT, self.OnUpdateFormatUI), (ID_USE_SOFTTABS, self.OnUpdateFormatUI), (ID_TO_UPPER, self.OnUpdateFormatUI), (ID_TO_LOWER, self.OnUpdateFormatUI), (ID_WORD_WRAP, self.OnUpdateFormatUI), (ID_EOL_MAC, self.OnUpdateFormatUI), (ID_EOL_WIN, self.OnUpdateFormatUI), (ID_EOL_UNIX, self.OnUpdateFormatUI), # Settings Menu (ID_AUTOCOMP, self.OnUpdateSettingsUI), (ID_AUTOINDENT, self.OnUpdateSettingsUI), (ID_SYNTAX, self.OnUpdateSettingsUI), (ID_FOLDING, self.OnUpdateSettingsUI), (ID_BRACKETHL, self.OnUpdateSettingsUI)]) # View Menu self._handlers['ui'].extend([(m_id, self.OnUpdateViewUI) for m_id in [ID_ZOOM_NORMAL, ID_ZOOM_IN, ID_ZOOM_OUT, ID_GOTO_MBRACE, ID_HLCARET_LINE, ID_SHOW_SB, ID_VIEW_TOOL, ID_SHOW_WS, ID_SHOW_EDGE, ID_SHOW_EOL, ID_SHOW_LN, ID_INDENT_GUIDES, ID_MAXIMIZE_EDITOR]]) # Lexer Menu self._handlers['ui'].extend([(l_id, self.OnUpdateLexerUI) for l_id in syntax.SYNTAX_IDS]) # Perspectives self._handlers['ui'].extend(self.GetPersectiveHandlers()) #---- End Menu Setup ----# #---- Other Event Handlers ----# # Frame self.Bind(wx.EVT_ACTIVATE, self.OnActivate) self.Bind(wx.EVT_CLOSE, self.OnClose) self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy, self) self.Bind(ed_event.EVT_STATUS, self.OnStatus) # Find Dialog self._handlers['menu'].extend(self.nb.GetMenuHandlers()) self._handlers['ui'].extend(self.nb.GetUiHandlers()) #---- End other event actions ----# #---- Final Setup Calls ----# self.LoadFileHistory(_PGET('FHIST_LVL', fmt='int')) # Call add on plugins self.LOG("[ed_main][info] Loading MainWindow Plugins") plgmgr = wx.GetApp().GetPluginManager() addons = MainWindowAddOn(plgmgr) addons.Init(self) self._handlers['menu'].extend(addons.GetEventHandlers()) self._handlers['ui'].extend(addons.GetEventHandlers(ui_evt=True)) shelf = ed_shelf.Shelf(plgmgr) self._shelf = shelf.Init(self) self._handlers['ui'].extend(shelf.GetUiHandlers(self._shelf)) self.LOG("[ed_main][info] Loading Generator plugins") generator.Generator(plgmgr).InstallMenu(menbar.GetMenuByName("tools")) # Set Perspective and other UI settings self.SetPerspective(_PGET('DEFAULT_VIEW')) self.PanelMgr.Update() # Make sure all clients are updated to user specified display font. ed_msg.PostMessage(ed_msg.EDMSG_DSP_FONT, _PGET('FONT3', 'font', wx.NORMAL_FONT)) # Message Handlers ed_msg.Subscribe(self.OnUpdateFileHistory, ed_msg.EDMSG_ADD_FILE_HISTORY) ed_msg.Subscribe(self.OnDoSessionSave, ed_msg.EDMSG_SESSION_DO_SAVE) ed_msg.Subscribe(self.OnDoSessionLoad, ed_msg.EDMSG_SESSION_DO_LOAD) # HACK: for gtk as most linux window managers manage the windows alpha # and set it when its created. wx.CallAfter(self.InitWindowAlpha) __name__ = u"MainWindow" def OnDestroy(self, evt): """Disconnect Message Handlers""" if self and evt.Id == self.Id: ed_msg.Unsubscribe(self.OnUpdateFileHistory) ed_msg.Unsubscribe(self.OnDoSessionSave) ed_msg.Unsubscribe(self.OnDoSessionLoad) evt.Skip() #---- End Private Member Functions/Variables ----# #---- Begin Public Member Function ----# def OnActivate(self, evt): """Activation Event Handler @param evt: wx.ActivateEvent """ if self._mlock.IsLocked(): # Deactivated for popup, leave handlers hooked up wx.UpdateUIEvent.SetMode(wx.UPDATE_UI_PROCESS_ALL) evt.Skip() return app = wx.GetApp() active = evt.GetActive() # Add or remove handlers from the event stack if active and not self._loaded: self._loaded = True app.SetTopWindow(self) # Slow the update interval to reduce overhead wx.UpdateUIEvent.SetUpdateInterval(215) wx.UpdateUIEvent.SetMode(wx.UPDATE_UI_PROCESS_SPECIFIED) self.SetExtraStyle(wx.WS_EX_PROCESS_UI_UPDATES) for handler in self._handlers['menu']: app.AddHandlerForID(*handler) for handler in self._handlers['ui']: app.AddUIHandlerForID(*handler) # HACK find better way to do this later. It seems that on gtk the # window doesn't get activated until later than it does on the # other platforms. So for panels that depend on updating their # initial state we need to send out a fake update message here. if wx.Platform == '__WXGTK__' and not self._initialized: self._initialized = True nb = self.GetNotebook() ed_msg.PostMessage(ed_msg.EDMSG_UI_NB_CHANGED, (nb, nb.GetSelection())) elif not active: self._loaded = False self.DeActivate() # Notify that window has become active/inactive ed_msg.PostMessage(ed_msg.EDMSG_UI_MW_ACTIVATE, dict(active=active), self.Id) evt.Skip() def OnUpdateFileHistory(self, msg): """Update filehistory menu for new files that were opened @param msg: Message object (data == filename) """ # May get notified after/during delete if self: try: self.filehistory.AddFileToHistory(msg.GetData()) except wx.PyAssertionError: # ignore errors that wxMac sometimes raises about unicode data pass def AddFileToHistory(self, fname): """Add a file to the windows file history as well as any other open windows history. @param fname: name of file to add @todo: change the file history to a centrally managed object that all windows pull from to avoid this quick solution. """ if _PGET('FHIST_LVL', 'int', 9) > 0: ed_msg.PostMessage(ed_msg.EDMSG_ADD_FILE_HISTORY, fname) def AddMenuHandler(self, menu_id, handler): """Add a menu event handler to the handler stack @param menu_id: Menu item id @param handler: Handler callable @postcondition: handler is added only if its not already in the set """ for item in self._handlers['menu']: if item[0] == menu_id: return else: self._handlers['menu'].append((menu_id, handler)) def AddUIHandler(self, menu_id, handler): """Add a UpdateUI event handler to the handler stack @param menu_id: Menu item id @param handler: Handler callable @postcondition: handler is added only if its not already in the set """ for item in self._handlers['ui']: if item[0] == menu_id: return else: self._handlers['ui'].append((menu_id, handler)) def DoOpen(self, evt, fname=u'', lnum=-1): """ Do the work of opening a file and placing it in a new notebook page. @keyword fname: can be optionally specified to open a file without opening a FileDialog @keyword lnum: Explicitly set the line number to open the file to """ try: e_id = evt.GetId() except AttributeError: e_id = evt if e_id == ID_OPEN: fdir = self.GetNotebook().GetCurrentCtrl().GetFileName() if len(fdir): fdir = os.path.dirname(fdir) elif not hasattr(sys, 'frozen'): fdir = os.curdir dlg = wx.FileDialog(self, _("Editra: Open"), fdir, "", ''.join(syntax.GenFileFilters()), wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR) dlg.SetFilterIndex(_PGET('FFILTER', 'int', 0)) if ebmlib.LockCall(self._mlock, dlg.ShowModal) == wx.ID_OK: _PSET('FFILTER', dlg.GetFilterIndex()) for path in dlg.GetPaths(): if _PGET('OPEN_NW', default=False): wx.GetApp().OpenNewWindow(path) else: self.nb.OpenPage(ebmlib.GetPathName(path), ebmlib.GetFileName(path)) self.nb.GoCurrentPage() dlg.Destroy() else: self.LOG("[ed_main][info] CMD Open File: %s" % fname) self.nb.OpenPage(ebmlib.GetPathName(fname), ebmlib.GetFileName(fname), quiet=True) self.nb.GoCurrentPage() # lnum arg is only used with command line open if lnum >= 0: buff = self.nb.GetCurrentCtrl() buff.GotoLine(lnum) self.Raise() def DeActivate(self): """Helper method for the App to tell this window to remove all its event handlers. """ self.SetExtraStyle(0) # HACK set update ui events back to process all here in case # opened dialog needs them. Not sure why this is necessary but it # is the only solution I could find to fix the external find # dialogs so that their buttons become enabled when typing in the # text control. # # If the windows that took the active position is another mainwindow # it will set the events back to UPDATE_UI_PROCESS_SPECIFIED to # prevent all the toolbars/menu items of each window from updating # when they dont need to. wx.UpdateUIEvent.SetMode(wx.UPDATE_UI_PROCESS_ALL) self.FlushEventStack() def FlushEventStack(self): """Clear the Menu and UpdateUI event handler stack @note: only unregisters this frames handlers from the app """ app = wx.GetApp() for handler in self._handlers['menu']: app.RemoveHandlerForID(handler[0]) for handler in self._handlers['ui']: app.RemoveUIHandlerForID(handler[0]) def GetCommandbar(self): """Get this windows command bar @return: ed_cmdbar.CommandBarBase """ return self._mpane.GetControlBar(wx.BOTTOM) def GetEditPane(self): """Get the editor notebook/command bar control @return: ed_mpane.MainPane """ return self._mpane def GetNotebook(self): """Get the windows main notebook that contains the editing buffers @return: reference to L{extern.flatnotebook.FlatNotebook} instance """ return getattr(self, 'nb', None) def GetShelf(self): """Get this windows Shelf @return: reference to L{iface.Shelf} instance @note: returns the plugin instance not the actual notebook, if a reference to the notebook is needed for parenting call GetWindow on the object returned by this function. """ return self._shelf def IsExiting(self): """Returns whether the windows is in the process of exiting or not. @return: boolean stating if the window is exiting or not """ return self._exiting def IsTopWindow(self): """Is this main window 'the' current top window @return: bool """ return wx.GetApp().GetTopWindow() == self def LoadFileHistory(self, size): """Loads file history from profile @return: None """ try: hist_list = _PGET('FHIST', default=list()) if len(hist_list) > size: hist_list = hist_list[:size] self.filehistory.History = hist_list except (Exception, wx.PyAssertionError), msg: self.LOG("[ed_main][err] Filehistory load failed: %s" % msg) def OnNew(self, evt): """Start a New File in a new tab @param evt: wx.MenuEvent """ if evt.GetId() == ID_NEW: self.nb.NewPage() self.nb.GoCurrentPage() else: evt.Skip() def OnOpen(self, evt): """Open a File @param evt: wx.MenuEvent """ if evt.GetId() == ID_OPEN: self.DoOpen(evt) else: evt.Skip() def OnFileHistory(self, evt): """Open a File from the File History @param evt: wx.MenuEvent """ fnum = evt.GetId() - wx.ID_FILE1 fname = self.filehistory.GetHistoryFile(fnum) # Check if file still exists if not os.path.exists(fname): mdlg = wx.MessageDialog(self, _("%s could not be found.\nPerhaps " "it's been moved or deleted.") % \ fname, _("File Not Found"), wx.OK | wx.ICON_WARNING) mdlg.CenterOnParent() ebmlib.LockCall(self._mlock, mdlg.ShowModal) mdlg.Destroy() # Remove offending file from history self.filehistory.RemoveFileFromHistory(fnum) else: self.DoOpen(evt, fname) def OnClosePage(self, evt): """Close a page @param evt: wx.MenuEvent """ if not self.IsActive(): evt.Skip() return e_id = evt.Id if e_id == ID_CLOSE: self.nb.ClosePage() elif e_id == ID_CLOSEALL: self.nb.CloseAllPages() else: evt.Skip() def SaveFile(self, tablbl, buf): """Save the given page in the notebook @param tablbl: main notebook tab label @param buf: EdEditView instance @note: intended for internal use! method signature may change """ fname = ebmlib.GetFileName(buf.GetFileName()) if fname != u'': fpath = buf.GetFileName() result = buf.SaveFile(fpath) self._last_save = fpath if result: self.PushStatusText(_("Saved File: %s") % fname, SB_INFO) else: err = buf.GetDocument().GetLastError() self.PushStatusText(_("ERROR: %s") % err, SB_INFO) ed_mdlg.SaveErrorDlg(self, fname, err) buf.GetDocument().ResetAll() else: self.OnSaveAs(ID_SAVEAS, tablbl, buf) def SaveCurrentBuffer(self): """Save the file in the currently selected editor buffer""" page = self.nb.GetSelection() self.SaveFile(self.nb.GetPageText(page), self.nb.GetCurrentCtrl()) def SaveAllBuffers(self): """Save all open editor buffers""" for page in range(self.nb.GetPageCount()): buff = self.nb.GetPage(page) if isinstance(buff, wx.stc.StyledTextCtrl): if buff.GetModify(): self.SaveFile(self.nb.GetPageText(page), buff) def OnSave(self, evt): """Save Current or All Buffers @param evt: wx.MenuEvent """ e_id = evt.Id if e_id == ID_SAVE: self.SaveCurrentBuffer() elif e_id == ID_SAVEALL: self.SaveAllBuffers() else: evt.Skip() return def OnSaveAs(self, evt, title=u'', page=None): """Save File Using a new/different name @param evt: wx.MenuEvent """ if page: ctrl = page else: ctrl = self.nb.GetCurrentCtrl() if title == u'': title = os.path.split(ctrl.GetFileName())[1] sdir = ctrl.GetFileName() if sdir is None or not len(sdir): sdir = self._last_save dlg = wx.FileDialog(self, _("Choose a Save Location"), os.path.dirname(sdir), title.lstrip(u"*"), u''.join(syntax.GenFileFilters()), wx.SAVE | wx.OVERWRITE_PROMPT) if ebmlib.LockCall(self._mlock, dlg.ShowModal) == wx.ID_OK: path = dlg.GetPath() dlg.Destroy() result = ctrl.SaveFile(path) fname = ebmlib.GetFileName(ctrl.GetFileName()) if not result: err = ctrl.GetDocument().GetLastError() ed_mdlg.SaveErrorDlg(self, fname, err) ctrl.GetDocument().ResetAll() self.PushStatusText(_("ERROR: Failed to save %s") % fname, SB_INFO) else: self._last_save = path self.PushStatusText(_("Saved File As: %s") % fname, SB_INFO) self.SetTitle("%s - file://%s" % (fname, ctrl.GetFileName())) self.nb.SetPageText(self.nb.GetSelection(), fname) self.nb.GetCurrentCtrl().FindLexer() self.nb.UpdatePageImage() self.AddFileToHistory(ctrl.GetFileName()) else: dlg.Destroy() def OnSaveProfile(self, evt): """Saves current settings as a profile @param evt: wx.MenuEvent """ if evt.Id == ID_SAVE_PROFILE: dlg = wx.FileDialog(self, _("Where to Save Profile?"), \ CONFIG['PROFILE_DIR'], "default.ppb", \ _("Profile") + " (*.ppb)|*.ppb", wx.SAVE | wx.OVERWRITE_PROMPT) if ebmlib.LockCall(self._mlock, dlg.ShowModal) == wx.ID_OK: profiler.TheProfile.Write(dlg.GetPath()) self.PushStatusText(_("Profile Saved as: %s") % \ dlg.GetFilename(), SB_INFO) dlg.Destroy() else: evt.Skip() def OnLoadProfile(self, evt): """Loads a profile and refreshes the editors state to match the settings found in the profile file. @param evt: wx.MenuEvent """ if evt.Id == ID_LOAD_PROFILE: dlg = wx.FileDialog(self, _("Load a Custom Profile"), CONFIG['PROFILE_DIR'], "default.ppb", _("Profile") + " (*.ppb)|*.ppb", wx.OPEN) if ebmlib.LockCall(self._mlock, dlg.ShowModal) == wx.ID_OK: profiler.TheProfile.Load(dlg.GetPath()) self.PushStatusText(_("Loaded Profile: %s") % \ dlg.GetFilename(), SB_INFO) dlg.Destroy() # Update editor to reflect loaded profile for win in wx.GetApp().GetMainWindows(): win.nb.UpdateTextControls() else: evt.Skip() def OnDoSessionSave(self, msg): """ed_msg interface for initiating a session save""" if msg.Context == self.Id: self.DoSaveSessionAs() def OnSaveSession(self, evt): """Save the current session of open files.""" if evt.Id == ID_SAVE_SESSION: self.DoSaveSessionAs() else: evt.Skip() def DoSaveSessionAs(self): """Prompt the user to save the current session""" mgr = ed_session.EdSessionMgr() cses = _PGET('LAST_SESSION', default=u"") if cses == mgr.DefaultSession: cses = u"" fname = ebmlib.LockCall(self._mlock, wx.GetTextFromUser, (_("Session Name"), _("Save Session"), cses)) fname = fname.strip() if fname: rval = self.nb.SaveSessionFile(fname) if rval is not None: wx.MessageBox(rval[1], rval[0], wx.OK|wx.ICON_ERROR) return _PSET('LAST_SESSION', fname) self.PushStatusText(_("Session Saved as: %s") % fname, SB_INFO) def OnDoSessionLoad(self, msg): """Initiate the loading of a session""" if msg.Context == self.Id: ses = msg.GetData() if ses: self.DoLoadSession(ses) def OnLoadSession(self, evt): """Load a saved session.""" if evt.Id == ID_LOAD_SESSION: mgr = ed_session.EdSessionMgr() sessions = mgr.GetSavedSessions() cses = _PGET('LAST_SESSION') if cses in sessions: sessions.remove(cses) if len(sessions) and (sessions[0] == mgr.DefaultSession): sessions[0] = _("Default") if cses == mgr.DefaultSession: cses = _("Default") fname = ebmlib.LockCall(self._mlock, wx.GetSingleChoice, (_("Session to Load:\nCurrent Session: '%s'") % cses, _("Load Session"), sessions)) if fname: self.DoLoadSession(fname) else: evt.Skip() def DoLoadSession(self, fname): """Load the specified session @param fname: session name """ if fname: mgr = ed_session.EdSessionMgr() if fname == _("Default"): fname = mgr.DefaultSession nbook = self.GetNotebook() rval = nbook.LoadSessionFile(fname) # Check for an error during load if rval is not None: wx.MessageBox(rval[1], rval[0], wx.OK|wx.ICON_WARNING) return _PSET('LAST_SESSION', fname) if fname == mgr.DefaultSession: fname = _("Default") self.PushStatusText(_("Loaded Session: %s") % fname, SB_INFO) def OnStatus(self, evt): """Update status text with messages from other controls @param evt: event that called this handler """ self.SetStatusText(evt.GetMessage(), evt.GetSection()) def OnPrint(self, evt): """Handles sending the current document to the printer, showing print previews, and opening the printer settings dialog. @todo: is any manual cleanup required for the printer objects? @param evt: wxMenuEvent """ e_id = evt.Id printer = MainWindow.PRINTER ctrl = self.nb.GetCurrentCtrl() if not ctrl: util.Log("[ed_main][warn] invalid control reference for printing: %s" % repr(ctrl)) wx.MessageBox(_("Failed to get control reference for printing"), _("Print failure"), wx.CENTER|wx.ICON_ERROR|wx.OK) return printer.SetStc(ctrl) printer.SetColourMode(_PGET('PRINT_MODE')) if e_id == ID_PRINT: printer.Print() elif e_id == ID_PRINT_PRE: printer.Preview() elif e_id == ID_PRINT_SU: printer.PageSetup() else: evt.Skip() def Close(self, force=False): """Close the window @param force: force the closer by vetoing the event handler """ if force: return super(MainWindow, self).Close(True) else: result = self.OnClose() return not result def OnClose(self, evt=None): """Close this frame and unregister it from the applications mainloop. @note: Closing the frame will write out all session data to the users configuration directory. @keyword evt: wx.MenuEvent @return: None on destroy, or True on cancel """ # Only auto-save session file if not using default session mgr = ed_session.EdSessionMgr() if _PGET('LAST_SESSION') == mgr.DefaultSession: self.nb.SaveCurrentSession() # Cleanup Controls self._exiting = True controls = self.nb.GetPageCount() self.LOG("[ed_main][evt] OnClose: Number of controls: %d" % controls) with eclib.Freezer(self) as _tmp: while controls: if controls <= 0: self.Close(True) # Force exit since there is a problem self.LOG("[ed_main][evt] OnClose: Requesting Page Close") if not self.nb.ClosePage(): self._exiting = False ed_msg.PostMessage(ed_msg.EDMSG_UI_NB_CHANGED, (self.nb, self.nb.GetSelection())) return True controls -= 1 ### If we get to here there is no turning back so cleanup ### additional items and save user settings # Write out saved document information self.nb.DocMgr.WriteBook() syntax.SyntaxMgr().SaveState() # Save Shelf contents _PSET('SHELF_ITEMS', self._shelf.GetItemStack()) _PSET('SHELF_LAYOUT', self._shelf.GetPerspective()) _PSET('SHELF_SELECTION', self._shelf.GetSelection()) # Save Window Size/Position for next launch self.UpdateAutoPerspective() # XXX On wxMac the window size doesnt seem to take the toolbar # into account so destroy it so that the window size is accurate. if wx.Platform == '__WXMAC__' and self.GetToolBar(): self.ToolBar.Destroy() # Raise the window from being iconized so that the size and position is # correct for the next launch (msw). if self.IsIconized(): self.Iconize(False) _PSET('WSIZE', self.GetSizeTuple()) _PSET('MAXIMIZED', self.IsMaximized()) _PSET('WPOS', self.GetPositionTuple()) self.LOG("[ed_main][evt] OnClose: Closing editor at pos=%s size=%s" % \ (_PGET('WPOS', 'str'), _PGET('WSIZE', 'str'))) # Cleanup file history # TODO: Find out why filehistory can be undefined by this point # sometimes. try: _PSET('FHIST', self.filehistory.History) except AttributeError: self.LOG("[ed_main][err] OnClose: Trapped AttributeError OnExit") # Update profile ppath = _PGET('MYPROFILE') profiler.TheProfile.Write(ppath) self.LOG("[ed_main][info] Saving profile to %s" % ppath) # Post exit notice to all aui panes panes = self.PanelMgr.GetAllPanes() exit_evt = ed_event.MainWindowExitEvent(ed_event.edEVT_MAINWINDOW_EXIT, wx.ID_ANY) for pane in panes: if pane.window: wx.PostEvent(pane.window, exit_evt) # Finally close the window self.LOG("[ed_main][evt] OnClose: Closing Main Frame") wx.GetApp().UnRegisterWindow(repr(self)) # Ensure that event handlers have been un registered from the app wx.UpdateUIEvent.SetMode(wx.UPDATE_UI_PROCESS_ALL) # Cleanup mpane = None for pane in self.PanelMgr.AllPanes: if pane and pane.window: win = pane.window if isinstance(win, ed_mpane.MainPanel): mpane = win continue elif self.PanelMgr.DetachPane(win): win.Destroy() # NOTE: wxBUG? calling destroy on the center pane results in # a pure virtual function call error. So just destroy # the child Notebook. if mpane: if mpane.Book: mpane.Book.Destroy() self.PanelMgr.UnInit() self.Destroy() #---- End File Menu Functions ----# #---- View Menu Functions ----# def OnShowStatusBar(self, evt): """Toggles visibility of status bar @param evt: wxMenuEvent """ if evt.Id == ID_SHOW_SB: show = not self.GetStatusBar().IsShown() _PSET('STATBAR', show) self.GetStatusBar().Show(show) self.SendSizeEvent() else: evt.Skip() def OnViewTb(self, evt): """Toggles visibility of toolbar @param evt: wxMenuEvent """ if evt.Id == ID_VIEW_TOOL: size = self.GetSize() toolbar = self.GetToolBar() if _PGET('TOOLBAR', 'bool', False) or toolbar.IsShown(): _PSET('TOOLBAR', False) toolbar.Hide() if wx.Platform != '__WXMAC__': self.SetSize((size[0], size[1] - toolbar.GetSize()[1])) else: _PSET('TOOLBAR', True) toolbar.Show() if wx.Platform != '__WXMAC__': self.SetSize((size[0], size[1] + toolbar.GetSize()[1])) self.SendSizeEvent() self.Refresh() self.Update() else: evt.Skip() def OnMaximizeEditor(self, evt): """Maximize the editor and hide the other panes. If the editor is already maximized, it is un-maximized and the other panes are restored @param evt: CommandEvent instance """ paneInfo = self.PanelMgr.GetPane("EditPane") if self.PanelMgr.IsEditorMaximized(): self.PanelMgr.RestorePane(paneInfo) ed_msg.PostMessage(ed_msg.EDMSG_UI_STC_RESTORE, context=self.GetId()) else: self.PanelMgr.MaximizePane(paneInfo) self.PanelMgr.Update() #---- End View Menu Functions ----# #---- Format Menu Functions ----# def OnFont(self, evt): """Open Font Settings Dialog for changing fonts on a per document basis. @note: This currently does not allow for font settings to stick from one session to the next. @param evt: wx.MenuEvent """ if evt.Id == ID_FONT: ctrl = self.nb.GetCurrentCtrl() fdata = wx.FontData() fdata.SetInitialFont(ctrl.GetDefaultFont()) dlg = wx.FontDialog(self, fdata) result = ebmlib.LockCall(self._mlock, dlg.ShowModal) data = dlg.GetFontData() dlg.Destroy() if result == wx.ID_OK: font = data.GetChosenFont() ctrl.SetGlobalFont(self.nb.control.FONT_PRIMARY, \ font.GetFaceName(), font.GetPointSize()) ctrl.SetGlobalFont(self.nb.control.FONT_SECONDARY, \ font.GetFaceName(), font.GetPointSize()) ctrl.UpdateAllStyles() else: evt.Skip() #---- End Format Menu Functions ----# #---- Tools Menu Functions ----# def OnStyleEdit(self, evt): """Opens the style editor @param evt: wx.MenuEvent """ if evt.Id == ID_STYLE_EDIT: import style_editor dlg = style_editor.StyleEditor(self) dlg.CenterOnParent() ebmlib.LockCall(self._mlock, dlg.ShowModal) dlg.Destroy() else: evt.Skip() def OnPluginMgr(self, evt): """Opens and shows Plugin Manager window @param evt: wx.MenuEvent """ if evt.Id == ID_PLUGMGR: import plugdlg win = wx.GetApp().GetWindowInstance(plugdlg.PluginDialog) if win is not None: win.Raise() return dlg = plugdlg.PluginDialog(self, wx.ID_ANY, PROG_NAME + " " \ + _("Plugin Manager"), \ size=wx.Size(550, 450)) dlg.CenterOnParent() dlg.Show() else: evt.Skip() def OnGenerate(self, evt): """Generates a given document type @pre: PluginMgr must be initialized and have active plugins that implement the Generator Interface @param evt: wx.MenuEvent """ gen = generator.Generator(wx.GetApp().GetPluginManager()) doc = gen.GenerateText(evt.Id, self.nb.GetCurrentCtrl()) if doc: self.nb.NewPage() ctrl = self.nb.GetCurrentCtrl() ctrl.SetText(doc[1]) ctrl.FindLexer(doc[0]) else: evt.Skip() #---- Misc Function Definitions ----# def DispatchToControl(self, evt): """Catches events that need to be passed to the current text control for processing. @param evt: wx.MenuEvent """ if not self.IsActive(): evt.Skip() return e_id = evt.Id ctrl = self.nb.GetCurrentCtrl() active_only = [ ID_ZOOM_IN, ID_ZOOM_OUT, ID_ZOOM_NORMAL, ID_JOIN_LINES, ID_CUT_LINE, ID_COPY_LINE, ID_INDENT, ID_UNINDENT, ID_TRANSPOSE, ID_TOGGLECOMMENT, ID_LINE_MOVE_UP, ID_LINE_MOVE_DOWN, ID_SELECTALL, ID_UNDO, ID_REDO, ID_CUT, ID_COPY, ID_PASTE, ID_LINE_BEFORE, ID_LINE_AFTER, ID_DUP_LINE, ID_PASTE_AFTER, ID_COLUMN_MODE, ID_TOGGLE_FOLD, ID_CYCLE_CLIPBOARD, ID_TOGGLE_ALL_FOLDS, ID_DELETE_LINE, ID_SHOW_AUTOCOMP, ID_SHOW_CALLTIP ] # Special handling for common clipboard related actions has_focus = self.FindFocus() is_stc = isinstance(has_focus, wx.stc.StyledTextCtrl) if has_focus is not None: if e_id == ID_PASTE and hasattr(has_focus, 'Paste'): has_focus.Paste() return elif e_id == ID_CYCLE_CLIPBOARD: start, end = has_focus.GetSelection() start, end = min(start, end), max(start, end) if is_stc: txt = has_focus.GetTextRange(start, end) elif hasattr(has_focus, 'GetRange'): txt = has_focus.GetRange(start, end) else: self.LOG("[ed_main][warn] no range meth in cycle clipboard") return if not MainWindow.CLIPBOARD.IsAtIndex(txt): MainWindow.CLIPBOARD.Reset() next = MainWindow.CLIPBOARD.GetNext() if is_stc: has_focus.ReplaceSelection(next) elif hasattr(has_focus, 'Replace'): has_focus.Replace(start, end, next) else: return has_focus.SetSelection(start, start+len(next)) return elif e_id == ID_CUT and hasattr(has_focus, 'Cut'): start, end = has_focus.GetSelection() if is_stc: txt = has_focus.GetTextRange(start, end) elif hasattr(has_focus, 'GetRange'): txt = has_focus.GetRange(start, end) MainWindow.CLIPBOARD.Put(txt) has_focus.Cut() return elif e_id == ID_COPY and hasattr(has_focus, 'Copy'): start, end = has_focus.GetSelection() if is_stc: txt = has_focus.GetTextRange(start, end) elif hasattr(has_focus, 'GetRange'): txt = has_focus.GetRange(start, end) MainWindow.CLIPBOARD.Put(txt) has_focus.Copy() return elif e_id == ID_REDO and hasattr(has_focus, 'Redo'): has_focus.Redo() return elif e_id == ID_UNDO and hasattr(has_focus, 'Undo'): has_focus.Undo() return elif e_id == ID_SELECTALL and hasattr(has_focus, 'SelectAll'): has_focus.SelectAll() return menu_ids = list(syntax.SYNTAX_IDS) menu_ids.extend([ID_SHOW_EOL, ID_SHOW_WS, ID_INDENT_GUIDES, ID_SYNTAX, ID_WORD_WRAP, ID_BRACKETHL, ID_EOL_MAC, ID_EOL_UNIX, ID_EOL_WIN, ID_NEXT_MARK, ID_PRE_MARK, ID_ADD_BM, ID_DEL_ALL_BM, ID_FOLDING, ID_AUTOCOMP, ID_SHOW_LN, ID_AUTOINDENT, ID_TAB_TO_SPACE, ID_SPACE_TO_TAB, ID_TRIM_WS, ID_SHOW_EDGE, ID_MACRO_START, ID_MACRO_STOP, ID_MACRO_PLAY, ID_TO_LOWER, ID_TO_UPPER, ID_USE_SOFTTABS, ID_GOTO_MBRACE, ID_HLCARET_LINE, ID_REVERT_FILE, ]) menu_ids.extend(active_only) if e_id in menu_ids: ctrl.ControlDispatch(evt) else: evt.Skip() return def OnReloadWithEnc(self, evt): """Reload the current file with a specified encoding @param evt: wx.MenuEvent """ if evt.Id == ID_RELOAD_ENC: ctrl = self.nb.GetCurrentCtrl() doc = ctrl.GetDocument() cenc = doc.GetEncoding() dlg = eclib.EncodingDialog(self.GetNotebook(), msg=_("Select an encoding to reload the file with"), title=_("Reload with Encoding"), default=cenc) bmp = wx.ArtProvider.GetBitmap(str(ID_DOCPROP), wx.ART_OTHER) if bmp.IsOk(): dlg.SetBitmap(bmp) dlg.CenterOnParent() if ebmlib.LockCall(self._mlock, dlg.ShowModal) == wx.ID_OK: nenc = dlg.GetEncoding() doc.SetEncoding(nenc) success = ctrl.ReloadFile()[0] if not success: msg = _("Failed to reload the file with: %(encoding)s") % dict(encoding=nenc) wx.MessageBox(msg, style=wx.OK|wx.ICON_ERROR) # Revert to previous encoding doc.SetEncoding(cenc) ctrl.ReloadFile() dlg.Destroy() else: evt.Skip() def OnPaneList(self, evt): """Navigates through panes @param evt: CommandEvent instance """ if evt.Id == ID_PANELIST: if self._paneNavi is not None: return bmp = wx.ArtProvider.GetBitmap(str(ID_NEW_WINDOW), wx.ART_MENU) self._paneNavi = eclib.AuiPaneNavigator(self, self.PanelMgr, bmp, _("Aui Pane Navigator")) self._paneNavi.SetReturnCode(wx.ID_OK) ebmlib.LockCall(self._mlock, self._paneNavi.ShowModal) sel = self._paneNavi.GetSelection() self._paneNavi.Destroy() self._paneNavi = None if isinstance(sel, basestring): paneInfo = self.PanelMgr.GetPane(sel) if paneInfo.IsOk(): if not paneInfo.IsShown(): paneInfo.Show() self.PanelMgr.Update() # Notify activation if the window supports it if hasattr(paneInfo.window, "OnShowAUIPane"): paneInfo.window.OnShowAUIPane() paneInfo.window.SetFocus() else: evt.Skip() # Menu Update Handlers def OnUpdateFileUI(self, evt): """Update filemenu items @param evt: EVT_UPDATE_UI """ if not self.IsActive(): return e_id = evt.Id ctrl = self.nb.GetCurrentCtrl() if e_id == ID_REVERT_FILE: evt.Enable(ctrl.GetModify()) elif e_id == ID_RELOAD_ENC: evt.Enable(len(ctrl.GetFileName())) else: evt.Skip() def OnUpdateClipboardUI(self, evt): """Update clipboard related menu/toolbar items @param evt: EVT_UPDATE_UI """ if not self.IsActive(): return e_id = evt.Id focus = self.FindFocus() enable = False if e_id == ID_UNDO: if hasattr(focus, 'CanUndo'): enable = focus.CanUndo() evt.Enable(enable) elif e_id == ID_REDO: if hasattr(focus, 'CanRedo'): enable = focus.CanRedo() evt.Enable(enable) elif e_id in (ID_PASTE, ID_PASTE_AFTER, ID_CYCLE_CLIPBOARD): if hasattr(focus, 'CanPaste'): enable = focus.CanPaste() evt.Enable(enable) elif e_id == ID_COPY: if hasattr(focus, 'CanCopy'): enable = focus.CanCopy() evt.Enable(enable) elif e_id == ID_CUT: if hasattr(focus, 'CanCut'): enable = focus.CanCut() evt.Enable(enable) elif e_id == ID_COLUMN_MODE: if hasattr(focus, 'IsColumnMode'): evt.Enable(True) else: evt.Enable(False) evt.Check(enable) else: evt.Skip() def OnUpdateFormatUI(self, evt): """Update status of format menu items @param evt: wxEVT_UPDATE_UI """ if not self.IsActive(): return e_id = evt.Id ctrl = self.nb.GetCurrentCtrl() if e_id == ID_USE_SOFTTABS: evt.Check(not bool(ctrl.GetUseTabs())) elif e_id == ID_WORD_WRAP: evt.Check(bool(ctrl.GetWrapMode())) elif e_id in [ID_EOL_MAC, ID_EOL_WIN, ID_EOL_UNIX]: evt.Check(ctrl.GetEOLModeId() == e_id) elif e_id in [ID_INDENT, ID_TO_UPPER, ID_TO_LOWER]: evt.Enable(ctrl.GetSelectionStart() != ctrl.GetSelectionEnd()) else: evt.Skip() def OnUpdateLexerUI(self, evt): """Update status of lexer menu @param evt: wxEVT_UPDATE_UI """ if not self.IsActive(): return e_id = evt.Id if e_id in syntax.SYNTAX_IDS: lang = self.nb.GetCurrentCtrl().GetLangId() evt.Check(lang == e_id) else: evt.Skip() def OnUpdateSettingsUI(self, evt): """Update settings menu items @param evt: wxEVT_UPDATE_UI """ if not self.IsActive(): return e_id = evt.Id ctrl = self.nb.GetCurrentCtrl() if e_id == ID_AUTOCOMP: evt.Check(ctrl.GetAutoComplete()) elif e_id == ID_AUTOINDENT: evt.Check(ctrl.GetAutoIndent()) elif e_id == ID_SYNTAX: evt.Check(ctrl.IsHighlightingOn()) elif e_id == ID_FOLDING: evt.Check(ctrl.IsFoldingOn()) elif e_id == ID_BRACKETHL: evt.Check(ctrl.IsBracketHlOn()) else: evt.Skip() def OnUpdateViewUI(self, evt): """Update status of view menu items @param evt: wxEVT_UPDATE_UI """ if not self.IsActive(): return e_id = evt.Id ctrl = self.nb.GetCurrentCtrl() zoom = ctrl.GetZoom() if e_id == ID_ZOOM_NORMAL: evt.Enable(zoom) elif e_id == ID_ZOOM_IN: evt.Enable(zoom < 18) elif e_id == ID_ZOOM_OUT: evt.Enable(zoom > -8) elif e_id == ID_GOTO_MBRACE: evt.Enable(-1 not in ctrl.GetBracePair()) elif e_id == ID_HLCARET_LINE: evt.Check(ctrl.GetCaretLineVisible()) elif e_id == ID_SHOW_SB: evt.Check(self.GetStatusBar().IsShown()) elif e_id == ID_VIEW_TOOL: evt.Check(self.GetToolBar().IsShown()) elif e_id == ID_SHOW_WS: evt.Check(bool(ctrl.GetViewWhiteSpace())) elif e_id == ID_SHOW_EDGE: evt.Check(bool(ctrl.GetEdgeMode())) elif e_id == ID_SHOW_EOL: evt.Check(bool(ctrl.GetViewEOL())) elif e_id == ID_SHOW_LN: evt.Check(bool(ctrl.GetMarginWidth(1))) elif e_id == ID_INDENT_GUIDES: evt.Check(bool(ctrl.GetIndentationGuides())) elif e_id == ID_MAXIMIZE_EDITOR: binder = self.MenuBar.GetKeyBinder() binding = binder.GetBinding(ID_MAXIMIZE_EDITOR) txt = _("Maximize Editor") if self.PanelMgr.IsEditorMaximized(): txt = _("Restore Editor") evt.SetText(txt + binding) else: evt.Skip() def OnCommandBar(self, evt): """Open the Commandbar @param evt: wx.MenuEvent """ e_id = evt.Id if e_id in (ID_QUICK_FIND, ID_GOTO_LINE, ID_COMMAND, ID_SESSION_BAR): self._mpane.ShowCommandControl(e_id) else: evt.Skip() def OnCustomizeLangMenu(self, evt): """Show the lexer menu customization dialog""" if evt.Id == ID_LEXER_CUSTOM: dlg = eclib.FilterDialog(self, title=_("Customize Menu"), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) mconfig = _PGET("LEXERMENU", default=list()) flters = dict() for item in syntax.SyntaxNames(): if item in mconfig: flters[item] = True else: flters[item] = False dlg.SetListValues(flters) dlg.SetInitialSize() dlg.CenterOnParent() if ebmlib.LockCall(self._mlock, dlg.ShowModal) == wx.ID_OK: includes = dlg.GetIncludes() includes.sort() _PSET("LEXERMENU", includes) ed_msg.PostMessage(ed_msg.EDMSG_CREATE_LEXER_MENU) dlg.Destroy() else: evt.Skip() def OnHelp(self, evt): """Handles help related menu events @param evt: wx.MenuEvent """ import webbrowser e_id = evt.Id if e_id == ID_HOMEPAGE: page = HOME_PAGE elif e_id == ID_DOCUMENTATION: page = HOME_PAGE + "/documentation" elif e_id == ID_TRANSLATE: page = I18N_PAGE elif e_id == ID_CONTACT: webbrowser.open("mailto:%s" % CONTACT_MAIL) return elif e_id == ID_BUG_TRACKER: page = "http://code.google.com/p/editra/issues/list" else: evt.Skip() return # It seems under some cases when running under windows the call to # subprocess in webbrowser will fail and raise an exception here. So # simply trap and ignore it. try: self.PushStatusText(_("Opening %s") % page, SB_INFO) webbrowser.open(page, 1) except: self.PushStatusText(_("Error: Unable to open %s") % page, SB_INFO) def PushStatusText(self, txt, field): """Override so that our custom status bar's method gets called do to these wxFrame methods not being exposed as virtuals. """ sb = self.GetStatusBar() if sb: sb.PushStatusText(txt, field) SetStatusText = PushStatusText def SetTitle(self, title=u''): """Sets the windows title @param title: The text to tag on to the default frame title """ name = u"%s v%s" % (PROG_NAME, VERSION) if len(title): name = u" - " + name super(MainWindow, self).SetTitle(title + name) def SetupToolBar(self): """Setup or reinitialize the windows ToolBar""" tb = self.GetToolBar() if tb: tb.Destroy() self.SetToolBar(ed_toolbar.EdToolBar(self)) self.ToolBar.Realize() self.GetToolBar().Show(_PGET('TOOLBAR')) self.Layout() @classmethod def UpdateClipboardRing(cls): """Update the clipboard ring to sync it with the system clipboard. @note: for internal use only """ try: txt = util.GetClipboardText() except wx.PyAssertionError: txt = None if txt is None or cls.CLIPBOARD.IsAtIndex(txt): return # Something new has come in from an external program cls.CLIPBOARD.Reset() cls.CLIPBOARD.Put(txt) #-----------------------------------------------------------------------------# # Event handlers that don't need to be part of the class def OnAbout(evt): """Show the About Dialog @param evt: wx.MenuEvent """ if evt.Id == ID_ABOUT: info = wx.AboutDialogInfo() year = time.localtime() desc = [_("Editra is a programmers text editor."), _("Written in 100%% Python."), _("Homepage") + ": " + HOME_PAGE + "\n", _("Platform Info") + ": (%s,%s)", _("License: wxWindows (see COPYING.txt for full license)")] desc = "\n".join(desc) py_version = sys.platform + ", python " + sys.version.split()[0] platform = list(wx.PlatformInfo[1:]) platform[0] += (" " + wx.VERSION_STRING) wx_info = ", ".join(platform) info.SetCopyright(_("Copyright") + "(C) 2005-%d Cody Precord" % year[0]) info.SetName(PROG_NAME.title()) info.SetDescription(desc % (py_version, wx_info)) info.SetVersion(VERSION) wx.AboutBox(info) else: evt.Skip() def OnPreferences(evt): """Open the Preference Panel @param evt: wx.MenuEvent """ if evt.Id == ID_PREF: cursor = wx.BusyCursor() win = wx.GetApp().GetWindowInstance(prefdlg.PreferencesDialog) if win is not None: win.Raise() else: dlg = prefdlg.PreferencesDialog(None) dlg.CenterOnParent() dlg.Show() del cursor else: evt.Skip() #-----------------------------------------------------------------------------# # Plugin interface to the MainWindow class MainWindowAddOn(plugin.Plugin): """Plugin that Extends the L{MainWindowI}""" observers = plugin.ExtensionPoint(iface.MainWindowI) def Init(self, window): """Call all observers once to initialize @param window: window that observers become children of """ for observer in self.observers: try: observer.PlugIt(window) except Exception, msg: util.Log("[ed_main][err] MainWindowAddOn.Init: %s" % msg) def GetEventHandlers(self, ui_evt=False): """Get Event handlers and Id's from all observers @keyword ui_evt: Get Update Ui handlers (default get menu handlers) @return: list [(ID_FOO, foo.OnFoo), (ID_BAR, bar.OnBar)] """ handlers = list() for observer in self.observers: try: items = None if ui_evt: if hasattr(observer, 'GetUIHandlers'): items = observer.GetUIHandlers() assert isinstance(items, list), "Must be a list()!" else: if hasattr(observer, 'GetMenuHandlers'): items = observer.GetMenuHandlers() assert isinstance(items, list), "Must be a list()!" except Exception, msg: util.Log("[ed_main][err] MainWindowAddOn.GetEventHandlers: %s" % str(msg)) continue if items is not None: handlers.extend(items) return handlers