diff options
author | rahulp13 | 2020-03-17 14:55:41 +0530 |
---|---|---|
committer | rahulp13 | 2020-03-17 14:55:41 +0530 |
commit | 296443137f4288cb030e92859ccfbe3204bc1088 (patch) | |
tree | ca4798c2da1e7244edc3bc108d81b462b537aea2 /lib/python2.7/site-packages/wx-3.0-msw/wx/tools/Editra/src/Editra.py | |
parent | 0db48f6533517ecebfd9f0693f89deca28408b76 (diff) | |
download | KiCad-eSim-296443137f4288cb030e92859ccfbe3204bc1088.tar.gz KiCad-eSim-296443137f4288cb030e92859ccfbe3204bc1088.tar.bz2 KiCad-eSim-296443137f4288cb030e92859ccfbe3204bc1088.zip |
initial commit
Diffstat (limited to 'lib/python2.7/site-packages/wx-3.0-msw/wx/tools/Editra/src/Editra.py')
-rw-r--r-- | lib/python2.7/site-packages/wx-3.0-msw/wx/tools/Editra/src/Editra.py | 1188 |
1 files changed, 1188 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/wx-3.0-msw/wx/tools/Editra/src/Editra.py b/lib/python2.7/site-packages/wx-3.0-msw/wx/tools/Editra/src/Editra.py new file mode 100644 index 0000000..db648de --- /dev/null +++ b/lib/python2.7/site-packages/wx-3.0-msw/wx/tools/Editra/src/Editra.py @@ -0,0 +1,1188 @@ +#!/usr/bin/env python2 +############################################################################### +# Name: Editra.py # +# Purpose: Implements Editras App object and the Main method # +# Author: Cody Precord <cprecord@editra.org> # +# Copyright: (c) 2008 Cody Precord <staff@editra.org> # +# License: wxWindows License # +############################################################################### + +""" +This module defines the Editra Application object and the Main method for +running Editra. + +@summary: Editra's main application object and MainLoop + +""" + +__author__ = "Cody Precord <cprecord@editra.org>" +__svnid__ = "$Id: Editra.py 71718 2012-06-12 13:25:48Z CJP $" +__revision__ = "$Revision: 71718 $" + +#--------------------------------------------------------------------------# +# Dependencies +import os +import sys + +# Due to some methods that were added in 2.8.3 being used in a large number +# of places Editra has become incompatible with wxPython 2.8.1.1 and earlier. +# So ensure correct version of wxPython can be loaded +if not hasattr(sys, 'frozen') and 'wx' not in sys.modules: + import wxversion + wxversion.ensureMinimal('2.8') + +import codecs +import base64 +import locale +import getopt +import shutil +import wx + +# The event handler mixin is now part of wxPython proper, but there hasn't +# been an official release with it yet, so try to import the official module +# but fallback to our own copy if it fails. +try: + import wx.lib.eventStack as events +except: + import extern.events as events + +# Try and import a system installed version of pkg_resources else fallback to +# the one bundled with Editra's source. +try: + from pkg_resources import resource_filename +except ImportError: + from extern.pkg_resources import resource_filename + +# Editra Libraries +import ed_glob +import ed_i18n +import profiler +import util +import dev_tool +import ed_main +import ed_art +import ed_txt +import ed_event +import updater +import plugin +import ed_ipc +import ed_session +import ebmlib +from syntax import synglob + +#--------------------------------------------------------------------------# +# Global Variables +ID_UPDATE_CHECK = wx.NewId() + +_ = wx.GetTranslation +#--------------------------------------------------------------------------# + +class Editra(wx.App, events.AppEventHandlerMixin): + """The Editra Application Object + @deprecated: L{GetMainWindow} + + """ + def __init__(self, *args, **kargs): + """Initialize that main app and its attributes + @postcondition: application is created and ready to be run in mainloop + + """ + wx.App.__init__(self, *args, **kargs) + events.AppEventHandlerMixin.__init__(self) + + # Attributes + self._log = dev_tool.DEBUGP + self._lock = False + self._windows = dict() + self._isexiting = False + + # Disable debug popups + wx.Log.EnableLogging(False) + # XXX: Temporary - disable assertions on OSX to work around + # upstream bug in drawing code "couldnt draw the rotated text" + if wx.Platform == '__WXMAC__': + self.SetAssertMode(wx.PYAPP_ASSERT_SUPPRESS) + + # Purge old logs + logfile = dev_tool.EdLogFile() + logfile.PurgeOldLogs(7) + + if ed_glob.SINGLE: + # Setup the instance checker + instance_name = u"%s-%s" % (self.GetAppName(), wx.GetUserId()) + lockpath = wx.StandardPaths.Get().GetTempDir() + self._instance = wx.SingleInstanceChecker(instance_name, path=lockpath) + if self._instance.IsAnotherRunning(): + try: + opts, args = ProcessCommandLine() + except getopt.GetoptError, msg: + self._log("[app][err] %s" % str(msg)) + args = list() + opts = dict() + + exml = ed_ipc.IPCCommand() + if len(args): + nargs = list() + for p in args: + try: + p = ebmlib.GetAbsPath(p) + except: + pass + fxml = ed_ipc.IPCFile() + fxml.value = p + nargs.append(fxml) + exml.filelist = nargs + arglist = list() + for arg, val in opts.items(): + axml = ed_ipc.IPCArg() + axml.name = arg + axml.value = val + arglist.append(axml) + exml.arglist = arglist + + # TODO: need to process other command line options as well i.e) -g + self._log("[app][info] Sending: %s" % exml.Xml) + key = profiler.Profile_Get('SESSION_KEY') + if ebmlib.IsUnicode(key): + key = key.encode(sys.getfilesystemencoding(), 'replace') + rval = ed_ipc.SendCommands(exml, key) + # If sending the command failed then let the editor startup + # a new instance + if not rval: + self._isfirst = True + else: + self._log("[app][info] Starting Ipc server...") + # Set the session key and save it to the users profile so + # that other instances can access the server + key = base64.b64encode(os.urandom(8), 'zZ') + uname = wx.GetUserName() + if ebmlib.IsUnicode(uname): + uname = uname.encode(sys.getfilesystemencoding(), 'replace') + key = uname + key + profiler.Profile_Set('SESSION_KEY', key) + profiler.Profile_Set('ISBINARY', hasattr(sys, 'frozen')) + path = profiler.Profile_Get('MYPROFILE') + profiler.TheProfile.Write(path) + try: + self._server = ed_ipc.EdIpcServer(self, key) + self._server.start() + except Exception, msg: + self._log("[app][err] Failed to start ipc server") + self._log("[app][err] %s" % str(msg)) + self._server = None + self._isfirst = True + else: + self._isfirst = True + + # Setup Plugins after locale as they may have resource that need to + # be loaded. + if self._isfirst: + self._pluginmgr = plugin.PluginManager() + + self._log("[app][info] Registering Editra's ArtProvider") + wx.ArtProvider.PushProvider(ed_art.EditraArt()) + + # Check if libenchant has been loaded or need to be + import extern.stcspellcheck as stcspellcheck + checker = stcspellcheck.STCSpellCheck + if not checker.isEnchantOk(): + spref = profiler.Profile_Get('SPELLCHECK', default=dict()) + libpath = spref.get('epath', u'') + checker.reloadEnchant(libpath) + # TODO: log if load fails here + + def AddMessageCatalog(self, name, path): + """Add a catalog lookup path to the app + @param name: name of catalog (i.e 'projects') + @param path: catalog lookup path + + """ + if self.locale is not None: + path = resource_filename(path, 'locale') + self.locale.AddCatalogLookupPathPrefix(path) + self.locale.AddCatalog(name) + + def OnInit(self): + """Initialize the Editor + @note: this gets called before __init__ + @postcondition: custom artprovider and plugins are loaded + + """ + self.SetAppName(ed_glob.PROG_NAME) + + self._log = dev_tool.DEBUGP + self._log("[app][info] Editra is Initializing") + + # Load user preferences + self.profile_updated = InitConfig() + self._isfirst = False # Is the first instance + self._instance = None + + # Setup Locale + locale.setlocale(locale.LC_ALL, '') + langId = ed_i18n.GetLangId(profiler.Profile_Get('LANG')) + if wx.Locale.IsAvailable(langId): + self.locale = wx.Locale(langId) + if self.locale.GetCanonicalName() in ed_i18n.GetAvailLocales(): + self._log("[app][info] Loaded Locale '%s'" % self.locale.CanonicalName) + self.locale.AddCatalogLookupPathPrefix(ed_glob.CONFIG['LANG_DIR']) + self.locale.AddCatalog(ed_glob.PROG_NAME) + else: + self._log("[app][err] Unknown Locale '%s'" % self.locale.CanonicalName) + del self.locale + self.locale = None + else: + self._log("[app][err] The locale %s is not available!" % profiler.Profile_Get('LANG')) + self.locale = None + + # Check and set encoding if necessary + d_enc = profiler.Profile_Get('ENCODING') + if not d_enc: + profiler.Profile_Set('ENCODING', ed_txt.DEFAULT_ENCODING) + else: + # Ensure the default encoding is valid + # Fixes up older installs on some systems that may have an + # invalid encoding set. + try: + codecs.lookup(d_enc) + except (LookupError, TypeError): + self._log("[app][err] Resetting bad encoding: %s" % d_enc) + profiler.Profile_Set('ENCODING', ed_txt.DEFAULT_ENCODING) + + # Setup the Error Reporter + if profiler.Profile_Get('REPORTER', 'bool', True): + sys.excepthook = dev_tool.ExceptionHook + + #---- Bind Events ----# + self.Bind(wx.EVT_ACTIVATE_APP, self.OnActivate) + self.Bind(wx.EVT_MENU, self.OnNewWindow, id=ed_glob.ID_NEW_WINDOW) + self.Bind(wx.EVT_MENU, self.OnCloseWindow) + self.Bind(ed_event.EVT_NOTIFY, self.OnNotify) + self.Bind(ed_ipc.EVT_COMMAND_RECV, self.OnCommandReceived) + + # Splash a warning if version is not a final version + if profiler.Profile_Get('APPSPLASH'): + import edimage + splash_img = edimage.splashwarn.GetBitmap() + self.splash = wx.SplashScreen(splash_img, wx.SPLASH_CENTRE_ON_PARENT | \ + wx.SPLASH_NO_TIMEOUT, 0, None, wx.ID_ANY) + self.splash.Show() + + return True + + def Destroy(self): + """Destroy the application""" + try: + # Cleanup the instance checker + del self._instance + except AttributeError: + pass + wx.App.Destroy(self) + + def DestroySplash(self): + """Destroy the splash screen""" + # If is created and not dead already + if getattr(self, 'splash', None) is not None and \ + isinstance(self.splash, wx.SplashScreen): + self.splash.Destroy() + self.splash = None + + def Exit(self, force=False): + """Exit the program + @postcondition: If no toplevel windows are present program will exit. + @postcondition: Program may remain open if an open window is locking. + + """ + self._isexiting = True + self._pluginmgr.WritePluginConfig() + profiler.TheProfile.Write(profiler.Profile_Get('MYPROFILE')) + if not self._lock or force: + if getattr(self, '_server', None): + self._server.Shutdown() + + try: + # Cleanup the instance checker + del self._instance + except AttributeError: + pass + + # Exit the app + wx.App.ExitMainLoop(self) + + def GetLocaleObject(self): + """Get the locale object owned by this app. Use this method to add + extra catalogs for lookup. + @return: wx.Locale or None + + """ + return self.locale + + def GetLog(self): + """Returns the logging function used by the app + @return: the logging function of this program instance + + """ + return self._log + + def GetMainWindow(self): + """Returns reference to the instance of the MainWindow + that is running if available, and None if not. + @return: the L{MainWindow} of this app if it is open + + """ + self._log("[app][warn] Editra::GetMainWindow is deprecated") + for window in self._windows: + if isinstance(self._windows[window][0], ed_main.MainWindow): + return self._windows[window][0] + return None + + def GetActiveWindow(self): + """Returns the active main window if there is one else it will + just return some main window or none if there are no main windows + @return: frame instance or None + + """ + awin = None + for win in self.GetMainWindows(): + if win.IsActive(): + awin = win + break + + if awin is None: + awin = self.GetTopWindow() + if not isinstance(awin, ed_main.MainWindow): + if len(self.GetMainWindows()): + awin = self.GetMainWindows()[0] + + return awin + + def GetCurrentBuffer(self): + """Get the current buffer from the active window or None + @return: EditraStc + + """ + win = self.GetTopWindow() + if not isinstance(win, ed_main.MainWindow): + win = self.GetActiveWindow() + if win is None: + return None # UI dead? + + if isinstance(win, ed_main.MainWindow): + nbook = win.GetNotebook() + if nbook: + return nbook.GetCurrentCtrl() + return None + + def GetMainWindows(self): + """Returns a list of all open main windows + @return: list of L{MainWindow} instances of this app (list may be empty) + + """ + mainw = list() + for window in self._windows: + try: + if isinstance(self._windows[window][0], ed_main.MainWindow): + mainw.append(self._windows[window][0]) + except AttributeError: + continue + return mainw + + def GetOpenWindows(self): + """Returns a list of open windows + @return: list of all open windows owned by app + + """ + return self._windows + + def GetPluginManager(self): + """Returns the plugin manager used by this application + @return: Apps plugin manager + @see: L{plugin} + + """ + return self._pluginmgr + + def GetProfileUpdated(self): + """Was the profile updated + @return: bool + + """ + return self.profile_updated + + def GetWindowInstance(self, wintype): + """Get an instance of an open window if one exists + @param wintype: Class type of window to look for + @precondition: Window must have called L{RegisterWindow} + @return: Instance of window or None + + """ + for win in self._windows: + if isinstance(self._windows[win][0], wintype): + return self._windows[win][0] + return None + + def IsLocked(self): + """Returns whether the application is locked or not + @return: whether a window has locked the app from closing or not + + """ + return self._lock + + def IsOnlyInstance(self): + """Check if this app is the the first instance that is running + @return: bool + + """ + return self._isfirst + + def Lock(self): + """Locks the app from exiting + @postcondition: program is locked from exiting + + """ + self._lock = True + + def OpenFile(self, filename, line=-1): + """Open a file in the currently active window + @param filename: file path + @keyword line: int + + """ + window = self.GetTopWindow() + if not isinstance(window, ed_main.MainWindow): + window = None + + try: + encoding = sys.getfilesystemencoding() + fname = ed_txt.DecodeString(filename, encoding) + + if profiler.Profile_Get('OPEN_NW', default=False): + self.OpenNewWindow(fname, window) + elif window: + window.DoOpen(ed_glob.ID_COMMAND_LINE_OPEN, fname, line) + + # Make sure the window is brought to the front + if window.IsIconized(): + window.Iconize(False) + window.Raise() + else: + # Some unlikely error condition + self._log("[app][err] OpenFile unknown error: %s" % filename) + + except Exception, msg: + self._log("[app][err] Failed to open file: %s" % str(msg)) + + def MacNewFile(self): + """Stub for future use""" + pass + + def MacOpenFile(self, filename): + """Macintosh Specific code for opening files that are associated + with the editor and double clicked on after the editor is already + running. + @param filename: file path string + @postcondition: if L{MainWindow} is open file will be opened in notebook + + """ + self._log("[app][info] MacOpenFile Fired") + self.OpenFile(filename, line=-1) + + def MacPrintFile(self, filename): + """Stub for future use + @param filename: file to print + + """ + pass + + def MacReopenApp(self): + """Handle kAEReopenApplication when dock icons is clicked on""" + frame = self.GetTopWindow() + if frame is not None: + if frame.IsIconized(): + frame.Iconize(False) + frame.Raise() + + def OnActivate(self, evt): + """Activation Event Handler + @param evt: wx.ActivateEvent + + """ + if evt.GetActive(): + self._log("[app][info] I'm Awake!!") + # Refresh Clipboard Ring + ed_main.MainWindow.UpdateClipboardRing() + +# frame = self.GetTopWindow() +# if frame is not None: +# if frame.IsIconized(): +# frame.Iconize(False) +# frame.Raise() + else: + self._log("[app][info] Going to sleep") + evt.Skip() + + def OnExit(self, evt=None, force=False): + """Handle application exit request + @keyword evt: event that called this handler + @keyword force: Force an exit + + """ + e_id = -1 + if evt: + e_id = evt.GetId() + + if e_id == ed_glob.ID_EXIT: + self._isexiting = True + # First loop is to ensure current top window is + # closed first + for win in self.GetMainWindows(): + if win.IsActive(): + result = win.Close() + if result: + self._isexiting = False + break + return + for win in self.GetMainWindows(): + win.Raise() + result = win.Close() + if not result: + self._isexiting = False + break + self.Exit(force) + else: + if evt: + evt.Skip() + + def OnNewWindow(self, evt): + """Create a new editing window + @param evt: wx.EVT_MENU + + """ + if evt.GetId() == ed_glob.ID_NEW_WINDOW: + frame = evt.GetEventObject().GetMenuBar().GetFrame() + self.OpenNewWindow(caller=frame) + else: + evt.Skip() + + def OnCommandReceived(self, evt): + """Receive commands from the IPC server + @todo: move command processing into own module + + """ + # Guard against events that come in after shutdown + # from server thread. + if not self or self._isexiting or not self.IsMainLoopRunning(): + return + + self._log("[app][info] IN OnCommandReceived") + cmds = evt.GetCommands() + if isinstance(cmds, ed_ipc.IPCCommand): + self._log("[app][info] OnCommandReceived %s" % cmds.Xml) + if not len(cmds.filelist): + self.OpenNewWindow() + else: + # TODO: change goto line handling to require one + # arg per file specified on the command line + # i.e) -g 23,44,100 + line = -1 + for argobj in cmds.arglist: + arg = argobj.name + if arg == '-g': + line = int(argobj.value) + if line > 0: + line -= 1 + break + + for fname in cmds.filelist: + self.OpenFile(fname.value, line) + + def OnCloseWindow(self, evt): + """Close the currently active window + @param evt: wx.MenuEvent + + """ + if evt.GetId() in [ed_glob.ID_CLOSE, ed_glob.ID_CLOSE_WINDOW]: + for window in wx.GetTopLevelWindows(): + if hasattr(window, 'IsActive') and window.IsActive(): + if hasattr(window, 'Close'): + window.Close() + break + else: + evt.Skip() + + def OpenNewWindow(self, fname=u'', caller=None): + """Open a new window + @keyword fname: Open a file in the new window + @keyword caller: MainWindow that called to open this one + @return: the new window + + """ + frame = ed_main.MainWindow(None, wx.ID_ANY, + profiler.Profile_Get('WSIZE'), + ed_glob.PROG_NAME) + if caller: + pos = caller.GetPosition() + frame.SetPosition((pos.x + 22, pos.y + 22)) + + self.RegisterWindow(repr(frame), frame, True) + self.SetTopWindow(frame) + if isinstance(fname, basestring) and fname != u'': + frame.DoOpen(ed_glob.ID_COMMAND_LINE_OPEN, fname) + frame.Show(True) + + # Ensure frame gets an Activate event when shown + # this doesn't happen automatically on windows + if wx.Platform == '__WXMSW__': + wx.PostEvent(frame, wx.ActivateEvent(wx.wxEVT_ACTIVATE, True)) + return frame + + def OnNotify(self, evt): + """Handle notification events + @param evt: L{ed_event.NotificationEvent} + + """ + e_val = evt.GetValue() + if evt.GetId() == ID_UPDATE_CHECK and \ + isinstance(e_val, tuple) and e_val[0]: + self.DestroySplash() + mdlg = wx.MessageDialog(self.GetActiveWindow(), + _("An updated version of Editra is available\n" + "Would you like to download Editra %s now?") %\ + e_val[1], _("Update Available"), + wx.YES_NO|wx.YES_DEFAULT|wx.CENTER|wx.ICON_INFORMATION) + if mdlg.ShowModal() == wx.ID_YES: + dl_dlg = updater.DownloadDialog(None, wx.ID_ANY, + _("Downloading Update")) + dp_sz = wx.GetDisplaySize() + dl_dlg.SetPosition(((dp_sz[0] - (dl_dlg.GetSize()[0] + 5)), 25)) + dl_dlg.Show() + mdlg.Destroy() + else: + evt.Skip() + + def RegisterWindow(self, name, window, can_lock=False): + """Registers winows with the app. The name should be the + repr of window. The can_lock parameter is a boolean stating + whether the window can keep the main app running after the + main frame has exited. + @param name: name of window + @param window: reference to window object + @keyword can_lock: whether window can lock exit or not + + """ + self._windows[name] = (window, can_lock) + + def ReloadArtProvider(self): + """Reloads the custom art provider onto the artprovider stack + @postcondition: artprovider is removed and reloaded + + """ + try: + wx.ArtProvider.PopProvider() + finally: + wx.ArtProvider.PushProvider(ed_art.EditraArt()) + + def UnLock(self): + """Unlocks the application + @postcondition: application is unlocked so it can exit + + """ + self._lock = False + + def UnRegisterWindow(self, name): + """Unregisters a named window with the app if the window + was the top window and if other windows that can lock are + registered in the window stack it will promote the next one + it finds to be the top window. If no windows that fit this + criteria are found it will close the application. + @param name: name of window to unregister + + """ + if name in self._windows: + self._windows.pop(name) + + if not len(self._windows): + self._log("[app][info] No more open windows shutting down") + self.Exit() + return + + # TODO: WXBUG? calling GetTopWindow when there are no more top + # level windows causes a crash under MSW. Moving this line + # above the previous check can reproduce the error. + cur_top = self.GetTopWindow() + if name == repr(cur_top): + found = False + for key in self._windows: + if self._windows[key][1]: + self._log("[app][info] Promoting %s to top" % key) + try: + self.SetTopWindow(self._windows[key][0]) + except Exception: + continue + found = True + break + + if not found: + self._log("[app][info] No more top windows exiting app") + self.UnLock() + self.Exit() + else: + self._log("[app][info] UnRegistered %s" % name) + else: + self._log("[app][warn] The window %s is not registered" % name) + + def WindowCanLock(self, winname): + """Checks if a named window can lock the application or + not. The window must have been previously registered with + a call to RegisterWindow for this function to have any + real usefullness. + @param winname: name of window to query + + """ + if winname in self._windows: + return self._windows[winname][1] + else: + self._log("[app][warn] the window %s has " + "not been registered" % winname) + return False + +#--------------------------------------------------------------------------# + +def InitConfig(): + """Initializes the configuration data + @postcondition: all configuration data is set + + """ + # Check if a custom config directory was specified on the commandline + if ed_glob.CONFIG['CONFIG_BASE'] is not None: + # TODO: there is a bug when the first time the config is created + # where the settings will not be saved until second launching. + config_base = os.path.abspath(ed_glob.CONFIG['CONFIG_BASE']) + else: + # Look for a profile directory on the system level. If this directory + # exists Use it instead of the user one. This will allow for running + # Editra from a portable drive or for system administrators to enforce + # settings on a system installed version. + config_base = util.ResolvConfigDir(u'.Editra', True) + + if os.path.exists(config_base): + ed_glob.CONFIG['CONFIG_BASE'] = config_base + ed_glob.CONFIG['PROFILE_DIR'] = os.path.join(config_base, u"profiles") + ed_glob.CONFIG['PROFILE_DIR'] += os.sep + ed_glob.CONFIG['ISLOCAL'] = True + else: + config_base = wx.StandardPaths.Get().GetUserDataDir() + ed_glob.CONFIG['PROFILE_DIR'] = util.ResolvConfigDir(u"profiles") + + # Check for if config directory exists and if profile is from the current + # running version of Editra. + profile_updated = False + if util.HasConfigDir() and os.path.exists(ed_glob.CONFIG['PROFILE_DIR']): + if profiler.ProfileIsCurrent(): + pstr = profiler.GetProfileStr() + # If using local(portable) config the profile string is stored + # as a relative path that just names the config file. + if ed_glob.CONFIG['ISLOCAL']: + pstr = os.path.join(ed_glob.CONFIG['PROFILE_DIR'], pstr) + pstr = util.RepairConfigState(pstr) + dev_tool.DEBUGP("[InitConfig][info] Loading profile: %s" % repr(pstr)) + profiler.TheProfile.Load(pstr) + else: + dev_tool.DEBUGP("[InitConfig][info] Updating Profile to current version") + + # When upgrading from an older version make sure all + # config directories are available. + for cfg in ("cache", "styles", "plugins", "profiles", "sessions"): + if not util.HasConfigDir(cfg): + util.MakeConfigDir(cfg) + + # Load and update profile + pstr = profiler.GetProfileStr() + pstr = util.RepairConfigState(pstr) + profiler.TheProfile.Load(pstr) + profiler.TheProfile.Update() + + #---- Temporary Profile Adaption ----# + + # Added after 0.5.32 + mconfig = profiler.Profile_Get('LEXERMENU', default=None) + if mconfig is None: + mconfig = [ synglob.LANG_C, synglob.LANG_CPP, + synglob.LANG_BASH, synglob.LANG_CSS, + synglob.LANG_HTML, synglob.LANG_JAVA, + synglob.LANG_LISP, synglob.LANG_PERL, + synglob.LANG_PHP, synglob.LANG_PYTHON, + synglob.LANG_RUBY, synglob.LANG_SQL, + synglob.LANG_XML] + mconfig.sort() + profiler.Profile_Set('LEXERMENU', mconfig) + + # GUI_DEBUG mode removed in 0.2.5 + mode = profiler.Profile_Get('MODE') + if mode == 'GUI_DEBUG': + profiler.Profile_Set('MODE', 'DEBUG') + + # This key has been removed so clean it from old profiles + profiler.Profile_Del('LASTCHECK') + + # Print modes don't use strings anymore + if isinstance(profiler.Profile_Get('PRINT_MODE'), basestring): + profiler.Profile_Set('PRINT_MODE', ed_glob.PRINT_BLACK_WHITE) + + # Simplifications to eol mode persistence (0.4.28) + # Keep for now till plugins are updated + #profiler.Profile_Del('EOL') # changed to EOL_MODE + + # After 0.4.65 LAST_SESSION now points a session file and not + # to a list of files to open. + ed_glob.CONFIG['SESSION_DIR'] = util.ResolvConfigDir(u"sessions") + smgr = ed_session.EdSessionMgr() + sess = profiler.Profile_Get('LAST_SESSION') + if isinstance(sess, list) or not sess: + profiler.Profile_Set('LAST_SESSION', smgr.DefaultSession) + else: + # After 0.6.58 session is reduced to a name instead of path + if sess and os.path.sep in sess: + name = smgr.SessionNameFromPath(sess) + profiler.Profile_Set('LAST_SESSION', name) + + #---- End Temporary Profile Adaption ----# + + # Write out updated profile + profiler.TheProfile.Write(pstr) + + profile_updated = True + else: + # Fresh install + util.CreateConfigDir() + + # Check and upgrade installs from old location + success = True + try: + success = UpgradeOldInstall() + except Exception, msg: + dev_tool.DEBUGP("[InitConfig][err] %s" % msg) + success = False + + if not success: + old_cdir = u"%s%s.%s%s" % (wx.GetHomeDir(), os.sep, + ed_glob.PROG_NAME, os.sep) + msg = ("Failed to upgrade your old installation\n" + "To retain your old settings you may need to copy some files:\n" + "\nFrom: %s\n\nTo: %s") % (old_cdir, config_base) + wx.MessageBox(msg, "Upgrade Failed", style=wx.ICON_WARNING|wx.OK) + + # Set default eol for windows + if wx.Platform == '__WXMSW__': + profiler.Profile_Set('EOL_MODE', ed_glob.EOL_MODE_CRLF) + profiler.Profile_Set('ICONSZ', (16, 16)) + elif wx.Platform == '__WXMAC__': + # Default to 32x32 toolbar icons on OSX + profiler.Profile_Set('ICONSZ', (32, 32)) + + #---- Profile Loaded / Installed ----# + + # Set debug mode + emode = profiler.Profile_Get('MODE') + if 'DEBUG' in emode: + ed_glob.DEBUG = True + if emode.startswith('VERBOSE'): + ed_glob.VDEBUG = True + + # Resolve resource locations + ed_glob.CONFIG['CONFIG_DIR'] = util.ResolvConfigDir(u"") + ed_glob.CONFIG['INSTALL_DIR'] = util.ResolvConfigDir(u"", True) + ed_glob.CONFIG['KEYPROF_DIR'] = util.ResolvConfigDir(u"ekeys", True) + ed_glob.CONFIG['SYSPIX_DIR'] = util.ResolvConfigDir(u"pixmaps", True) + ed_glob.CONFIG['PLUGIN_DIR'] = util.ResolvConfigDir(u"plugins") + ed_glob.CONFIG['THEME_DIR'] = util.ResolvConfigDir(os.path.join(u"pixmaps", u"theme")) + ed_glob.CONFIG['LANG_DIR'] = util.ResolvConfigDir(u"locale", True) + ed_glob.CONFIG['STYLES_DIR'] = util.ResolvConfigDir(u"styles") + ed_glob.CONFIG['SYS_PLUGIN_DIR'] = util.ResolvConfigDir(u"plugins", True) + ed_glob.CONFIG['SYS_STYLES_DIR'] = util.ResolvConfigDir(u"styles", True) + ed_glob.CONFIG['TEST_DIR'] = util.ResolvConfigDir(os.path.join(u"tests", u"syntax"), True) + + # Make sure all standard config directories are there + for cfg in ("cache", "styles", "plugins", "profiles", "sessions"): + if not util.HasConfigDir(cfg): + util.MakeConfigDir(cfg) + ed_glob.CONFIG['CACHE_DIR'] = util.ResolvConfigDir(u"cache") + ed_glob.CONFIG['SESSION_DIR'] = util.ResolvConfigDir(u"sessions") + + return profile_updated + +#--------------------------------------------------------------------------# + +def UpgradeOldInstall(): + """Upgrade an old installation and transfer all files if they exist + @note: FOR INTERNAL USE ONLY + @return: bool (True if success, False if failure) + + """ + old_cdir = u"%s%s.%s%s" % (wx.GetHomeDir(), os.sep, + ed_glob.PROG_NAME, os.sep) + base = ed_glob.CONFIG['CONFIG_BASE'] + if base is None: + base = wx.StandardPaths.Get().GetUserDataDir() + os.sep + + err = 0 + if os.path.exists(old_cdir) and \ + base.lower().rstrip(os.sep) != old_cdir.lower().rstrip(os.sep): + for item in os.listdir(old_cdir): + try: + dest = os.path.join(base, item) + item = os.path.join(old_cdir, item) + if os.path.exists(dest): + if os.path.isdir(dest): + shutil.rmtree(dest, True) + else: + os.remove(dest) + + shutil.move(item, dest) + except Exception, msg: + util.Log("[Upgrade][err] %s" % msg) + err += 1 + continue + + os.rmdir(old_cdir) + + # Load the copied over profile + pstr = profiler.GetProfileStr() + prof = os.path.basename(pstr) + pstr = os.path.join(base, u"profiles", prof) + if os.path.exists(pstr): + profiler.TheProfile.Load(pstr) + profiler.TheProfile.Update() + profiler.UpdateProfileLoader() + + if not err: + wx.MessageBox(_("Your profile has been updated to the latest " + "version") + u"\n" + \ + _("Please check the preferences dialog to check " + "your preferences"), + _("Profile Updated")) + + return not err + +#--------------------------------------------------------------------------# + +def PrintHelp(err=None): + """Print command line help + @postcondition: Help is printed and program exits + + """ + if err is not None: + sys.stderr.write(err + os.linesep) + + print(("Editra - %s - Developers Text Editor\n" + "Cody Precord (2005-2012)\n\n" + "usage: Editra [arguments] [files... ]\n\n" + "Short Arguments:\n" + " -c Set custom configuration directory at runtime\n" + " -d Turn on console debugging (-dd for verbose debug)\n" + " -D Turn off console debugging (overrides preferences)\n" + " -g Open file to line (i.e Editra -g 10 file.txt)\n" + " -h Show this help message\n" + " -p Run Editra in the profiler (outputs to editra.prof).\n" + " -v Print version number and exit\n" + " -S Disable single instance checker\n" + "\nLong Arguments:\n" + " --confdir arg Set custom configuration directory at runtime\n" + " --debug Turn on console debugging\n" + " --help Show this help message\n" + " --auth Print the ipc server info\n" + " --version Print version number and exit\n" + " --profileOut arg Run Editra in the profiler (arg is output file)\n" + ) % ed_glob.VERSION) + + if err is None: + os._exit(0) + else: + os._exit(1) + +#--------------------------------------------------------------------------# + +def ProcessCommandLine(): + """Process the command line switches + @return: tuple ({switches,}, [args,]) + + """ + try: + items, args = getopt.getopt(sys.argv[1:], "dg:hp:vDSc:", + ['debug', 'help', 'version', 'auth', + 'confdir=', 'profileOut=']) + except getopt.GetoptError, msg: + # Raise error to console and exit + PrintHelp(str(msg)) + + # Process command line options + opts = dict(items) + for opt, value in dict(opts).items(): + if opt in ['-h', '--help']: + PrintHelp() + elif opt in ['-v', '--version']: + print(ed_glob.VERSION) + os._exit(0) + elif opt in ['-d', '--debug'] and '-D' not in opts.keys(): + # If the debug flag is set more than once go into verbose mode + if ed_glob.DEBUG: + ed_glob.VDEBUG = True + ed_glob.DEBUG = True + opts.pop(opt) + elif opt == '-D': + ed_glob.DEBUG = False + ed_glob.VDEBUG = False + opts.pop('-D') + elif opt == '-S': + # Disable single instance checker + ed_glob.SINGLE = False + opts.pop(opt) + elif opt in ['-c', '--confdir']: + ed_glob.CONFIG['CONFIG_BASE'] = value + opts.pop(opt) + elif opt == '--profileOut': + opts['-p'] = value + opts.pop('--profileOut') + elif opt == '-g': + # Validate argument passed to -g + if not value.isdigit(): + PrintHelp("error: -g requires a number as an argument!") + else: + pass + + # Return any unprocessed arguments + return opts, args + +#--------------------------------------------------------------------------# + +def Main(): + """Configures and Runs an instance of Editra + @summary: Parses command line options, loads the user profile, creates + an instance of Editra and starts the main loop. + + """ + opts, args = ProcessCommandLine() + + if '-p' in opts: + p_file = opts['-p'] + opts.pop('-p') + + if not len(p_file): + # Fall back to default output file + p_file = "editra.prof" + + import hotshot + prof = hotshot.Profile(p_file) + prof.runcall(_Main, opts, args) + prof.close() + else: + _Main(opts, args) + +def _Main(opts, args): + """Main method + @param opts: Commandline options + @param args: Commandline arguments + + """ + # Put extern subpackage on path so that bundled external dependencies + # can be found if needed. + if not hasattr(sys, 'frozen'): + epath = os.path.join(os.path.dirname(__file__), 'extern') + if os.path.exists(epath): + sys.path.append(epath) + + # Create Application + dev_tool.DEBUGP("[main][app] Initializing application...") + editra_app = Editra(False) + + # Print ipc server authentication info + if '--auth' in opts: + opts.pop('--auth') + print "port=%d,key=%s" % (ed_ipc.EDPORT, + profiler.Profile_Get('SESSION_KEY')) + + # Check if this is the only instance, if its not exit since + # any of the opening commands have already been passed to the + # master instance + if not editra_app.IsOnlyInstance(): + dev_tool.DEBUGP("[main][info] Second instance exiting...") + editra_app.Destroy() + os._exit(0) + + # Set the timeout on destroying the splash screen + wx.CallLater(2300, editra_app.DestroySplash) + + if profiler.Profile_Get('SET_WSIZE'): + wsize = profiler.Profile_Get('WSIZE') + else: + wsize = (700, 450) + frame = ed_main.MainWindow(None, wx.ID_ANY, wsize, ed_glob.PROG_NAME) + frame.Maximize(profiler.Profile_Get('MAXIMIZED')) + editra_app.RegisterWindow(repr(frame), frame, True) + editra_app.SetTopWindow(frame) + frame.Show(True) + + # Load Session Data + # But not if there are command line args for files to open + if profiler.Profile_Get('SAVE_SESSION', 'bool', False) and not len(args): + smgr = ed_session.EdSessionMgr() + session = profiler.Profile_Get('LAST_SESSION', default=u'') + if isinstance(session, list): + # Check for format conversion from previous versions + profiler.Profile_Set('LAST_SESSION', smgr.DefaultSession) + session = smgr.DefaultSession + frame.GetNotebook().LoadSessionFile(session) + del session + + # Unlike wxMac/wxGTK Windows doesn't post an activate event when a window + # is first shown, so do it manually to make sure all event handlers get + # pushed. + if wx.Platform == '__WXMSW__': + wx.PostEvent(frame, wx.ActivateEvent(wx.wxEVT_ACTIVATE, True)) + + # Do update check if preferences say its ok to do so + isadmin = os.access(ed_glob.CONFIG['INSTALL_DIR'], os.R_OK|os.W_OK) + if isadmin and profiler.Profile_Get('CHECKUPDATE', default=True): + uthread = updater.UpdateThread(editra_app, ID_UPDATE_CHECK) + uthread.start() + + if len(args): + line = -1 + if '-g' in opts: + line = max(0, int(opts.pop('-g')) - 1) + + # TODO: should line arg only be applied to the first file name or all? + # currently apply to all. + for arg in args: + try: + fname = ed_txt.DecodeString(arg, sys.getfilesystemencoding()) + fname = ebmlib.GetAbsPath(fname) + frame.DoOpen(ed_glob.ID_COMMAND_LINE_OPEN, fname, line) + except IndexError: + dev_tool.DEBUGP("[main][err] IndexError on commandline args") + + # Notify that profile was updated + if editra_app.GetProfileUpdated(): + editra_app.DestroySplash() + # Make sure window iniliazes to default position + profiler.Profile_Del('WPOS') + wx.MessageBox(_("Your profile has been updated to the latest " + "version") + u"\n" + \ + _("Please check the preferences dialog to verify " + "your preferences"), + _("Profile Updated")) + + # 3. Start Applications Main Loop + dev_tool.DEBUGP("[main][info] Starting MainLoop...") + wx.CallAfter(frame.Raise) + + # Install handlers to exit app if os is shutting down/restarting + ebmlib.InstallTermHandler(editra_app.Exit, force=True) + + editra_app.MainLoop() + dev_tool.DEBUGP("[main][info] MainLoop finished exiting application") + os._exit(0) + +#-----------------------------------------------------------------------------# +if __name__ == '__main__': + Main() |