#!/usr/bin/env python #---------------------------------------------------------------------- # Name: Boa.py # Purpose: The main file for Boa. # # Author: Riaan Booysen # # Created: 1999 # RCS-ID: $Id: Boa.py,v 1.49 2005/07/04 13:51:24 riaan Exp $ # Copyright: (c) 1999 - 2005 Riaan Booysen # Licence: GPL #---------------------------------------------------------------------- #Boa:App:BoaApp """ The __main__ file for Boa. Handles creation/initialisation of main objects and commandline arguments """ import sys, os, string, time, warnings #try: import psyco; psyco.full() #except ImportError: pass t1 = time.time() # This flag determines if Boa should try to send the filename via a socket to an # already running instance of Boa. There is another flag under Preferences # which determines if Boa should create and listen on the socket. server_mode = 1 main_script = 'Boa.py' trace_mode = 'functions' # 'lines' trace_save = 'all'#'lastline' # 'all' def trace_func(frame, event, arg): """ Callback function when Boa runs in tracing mode""" if frame and tracefile: info = '%s|%d|%d|%s|\n' % (frame.f_code.co_filename, frame.f_lineno, id(frame), event) if trace_save == 'lastline': tracefile.seek(0) tracefile.write(info) tracefile.flush() return trace_func def get_current_frame(): try: raise 'get_exc_info' except: return sys.exc_info()[2].tb_frame.f_back def sendToRunningBoa(names, host='127.0.0.1', port=50007): import socket try: if names: print 'Sent', for name in names: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((host, port)) # do not change files of form [prot]://[path] if name.find('://') == -1: name = os.path.abspath(name) s.send(name) print name, s.close() print except socket.error: return 0 else: return 1 startupErrors = [] import __version__ # Command line options doDebug = constricted = emptyEditor = blockSocketServer = 0 startupfile = '' startupModules = () startupEnv = os.environ.get('BOASTARTUP') or os.environ.get('PYTHONSTARTUP') def processArgs(argv): _doDebug = _doRemoteDebugSvr = _constricted = _emptyEditor = 0 _blockSocketServer = 0 _startupfile = '' _startupModules = () import getopt try: optlist, args = getopt.getopt(argv, 'CDTSBO:ERNHVhv', ['Constricted', 'Debug', 'Trace', 'StartupFile', 'BlockHomePrefs', 'OverridePrefsDirName', 'EmptyEditor', 'RemoteDebugServer', 'NoCmdLineTransfer', 'Help', 'Version', 'help', 'version']) except getopt.GetoptError, err: print 'Error: %s'%str(err) print 'For options: Boa.py --help' sys.exit() if (('-D', '') in optlist or ('--Debug', '') in optlist) and len(args): # XXX should be able to 'debug in running Boa' _doDebug = 1 elif (('-R', '') in optlist or ('--RemoteDebugServer', '') in optlist) and len(args): _doRemoteDebugSvr = 1 elif ('-T', '') in optlist or ('--Trace', '') in optlist: print 'Running in trace mode.' global tracefile tracefile = open('Boa.trace', 'wt') tracefile.write(os.getcwd()+'\n') trace_func(get_current_frame().f_back, 'call', None) trace_func(get_current_frame(), 'call', None) if trace_mode == 'functions': sys.setprofile(trace_func) elif trace_mode == 'lines': sys.settrace(trace_func) if len(args): # XXX Only the first file appears in the list when multiple files # XXX are drag/dropped on a Boa shortcut, why? _startupModules = args if ('-S', '') in optlist or ('--StartupFile', '') in optlist: _startupfile = startupEnv if ('-C', '') in optlist or ('--Constricted', '') in optlist: _constricted = 1 if ('-E', '') in optlist or ('--EmptyEditor', '') in optlist: _emptyEditor = 1 if ('-N', '') in optlist or ('--NoCmdLineTransfer', '') in optlist: _blockSocketServer = 1 if ('-h', '') in optlist or ('--help', '') in optlist or \ ('-H', '') in optlist or ('--Help', '') in optlist: print 'Boa Constructor (%s)'%__version__.version print 'Command-line usage: %s [options] [file1] [file2] ...'%main_script print '-C, --Constricted:' print '\tRuns in constricted mode, overrides the Preference' print '-D, --Debug:' print '\tRuns the first filename passed on the command-line in the Debugger ' print '\ton startup' print '-T, --Trace:' print '\tRuns in traceing mode. Used for tracking down core dumps. Every ' print '\tfunction call is logged to a file which can later be parsed for ' print '\ta traceback' print '-S, --StartupFile:' print '\tExecutes the script pointed to by $BOASTARTUP or '\ '$PYTHONSTARTUP in' print '\tthe Shell namespace. The Editor object is available as sys.boa_ide.' print '\tOverrides the Preference' print '-B, --BlockHomePrefs:' print '\tPrevents the $HOME directory being used ' print '-O dirname, --OverridePrefsDirName dirname:' print '\tSpecify a different directory to load Preferences from.' print '\tDefault is .boa and is used if it exists' print '\tDirectory will be created (and populated) if it does not exist' print '-E, --EmptyEditor:' print "\tDon't open the files that were open last time Boa was closed." print '-R, --RemoteDebugServer:' print '\tRuns the first filename passed on the command-line in a ' print '\tRemote Debugger Server that can be connected to over a socket.' print '-N, --NoCmdLineTransfer:' print "\tDon't transfer command line options to a running Boa, start a " print '\tnew instance.' print '-H, --Help, --help:' print '\tThis page.' sys.exit() if ('-v', '') in optlist or ('--version', '') in optlist or \ ('-V', '') in optlist or ('--Version', '') in optlist: print 'Version: %s'%__version__.version sys.exit() return (_doDebug, _startupfile, _startupModules, _constricted, _emptyEditor, _doRemoteDebugSvr, _blockSocketServer, optlist, args) # This happens as early as possible (before wxPython loads) to make filename # transfer to a running Boa as quick as possible and little NS pollution if __name__ == '__main__' and len(sys.argv) > 1: (doDebug, startupfile, startupModules, constricted, emptyEditor, doDebugSvr, blockSocketServer, opts, args) = processArgs(sys.argv[1:]) if doDebugSvr and startupModules: print 'Running as a Remote Debug Server' from Debugger.RemoteServer import start # XXX username, password optionally should be on the command-line start(username='', password='') # startupModules contain everything from the first filename and on sys.argv = startupModules sys.path.insert(0, os.path.abspath(os.path.dirname(sys.argv[0]))) execfile(sys.argv[0], {'__name__': '__main__', '__builtins__': __builtins__}) sys.exit() # Try connect to running Boa using sockets, tnx to Tim Hochberg if not blockSocketServer and startupModules and server_mode: if sendToRunningBoa(startupModules): print 'Transfered arguments to running Boa, exiting.' sys.exit() print 'Starting Boa Constructor v%s'%__version__.version print 'importing wxPython' try: # See if there is a multi-version install of wxPython import wxversion wxversion.ensureMinimal('2.5') except ImportError: # Otherwise assume a normal 2.4 install, if it isn't 2.4 it will # be caught below pass ### silence wxPython's bool deprecations ##from wxPython import wx ##try: ## # wxPy 2.4.0.4 and Py 2.2 and 2.3 ## wx.True = True ## wx.False = False ##except NameError: ## try: ## # wxPy 2.4.0.4 and Py 2.1 ## wx.True = wx.True ## wx.False = wx.False ## except AttributeError: ## # earlier wxPys ## pass import wx wx.RegisterId(15999) #warnings.filterwarnings('ignore', '', DeprecationWarning, 'wxPython.imageutils') # Use package version string as it is the only one containing bugfix version number import wx # Remove non number/dot characters wxVersion = wx.__version__ for c in wxVersion: if c not in string.digits+'.': wxVersion = wxVersion.replace(c, '') wxVersion = tuple(map(lambda v: int(v), (wxVersion.split('.')+['0'])[:4])) if wxVersion < __version__.wx_version: wx.PySimpleApp() wx.MessageBox('Sorry! This version of Boa requires at least '\ 'wxPython %d.%d.%d.%d'%__version__.wx_version, 'Version error', wx.OK | wx.ICON_ERROR) raise 'wxPython >= %d.%d.%d.%d required'%__version__.wx_version if __version__.wx_version_max and wxVersion > __version__.wx_version_max: wx.PySimpleApp() wx.MessageBox('Sorry! This version of Boa does not work under '\ 'wxPython %d.%d.%d.%d, please downgrade to '\ 'wxPython %d.%d.%d.%d'% (wxVersion+__version__.wx_version_max), 'Version error', wx.OK | wx.ICON_ERROR) raise 'wxPython %d.%d.%d.%d not supported'%wxVersion import Preferences, Utils import About print 'running main...' # XXX auto created frames (main frame handled currently) # XXX More property editors! # XXX More companion classes! $ # XXX Find: Exceptions should not cancel the search # XXX Refactor PropertyEditor/Companion/Inspector interfaces # XXX Support IDLE extensions # XXX Code completion # XXX self.qwerty = qwerty # XXX wipes '= qwerty' when qwerty is selected # XXX Renaming Boa.jpg in root fails # XXX Save as after app is closed # XXX Add wx.ImageBitmap, delete (prints class link error) modules ={'About': [0, 'About box and Splash screen', 'About.py'], 'AppViews': [0, 'Views for the AppModel', 'Views/AppViews.py'], 'BaseCompanions': [0, '', 'Companions/BaseCompanions.py'], 'BasicCompanions': [0, '', 'Companions/BasicCompanions.py'], 'BicycleRepairMan.plug-in': [0, '', 'Plug-ins/BicycleRepairMan.plug-in.py'], 'Breakpoint': [0, '', 'Debugger/Breakpoint.py'], 'Browse': [0, 'History for navigation through the IDE', 'Browse.py'], 'ButtonCompanions': [0, '', 'Companions/ButtonCompanions.py'], 'CPPSupport': [0, '', 'Models/CPPSupport.py'], 'CVSExplorer': [0, '', 'Explorers/CVSExplorer.py'], 'ChildProcessClient': [0, '', 'Debugger/ChildProcessClient.py'], 'ChildProcessServer': [0, '', 'Debugger/ChildProcessServer.py'], 'ChildProcessServerStart': [0, '', 'Debugger/ChildProcessServerStart.py'], 'ClassBrowser': [0, 'Frame that displays the wxPython object hierarchy by Class and Module', 'ClassBrowser.py'], 'ClipboardPlus.plug-in': [0, '', 'Plug-ins/ClipboardPlus.plug-in.py'], 'CollectionEdit': [0, '', 'Views/CollectionEdit.py'], 'ComCompanions': [0, 'Companion classes for COM (win32 only)', 'Companions/ComCompanions.py'], 'Companions': [0, 'Most visual wxPython class companions ', 'Companions/Companions.py'], 'ConfigSupport': [0, '', 'Models/ConfigSupport.py'], 'Constructors': [0, 'Constructor signature mixin classes', 'Companions/Constructors.py'], 'ContainerCompanions': [0, '', 'Companions/ContainerCompanions.py'], 'Controllers': [0, '', 'Models/Controllers.py'], 'CreationOrdDlg': [0, '', 'Views/CreationOrdDlg.py'], 'CtrlAlign': [0, '', 'Views/CtrlAlign.py'], 'CtrlSize': [0, '', 'Views/CtrlSize.py'], 'Cyclops': [0, '', 'ExternalLib/Cyclops.py'], 'DAVExplorer': [0, '', 'Explorers/DAVExplorer.py'], 'DataView': [0, 'View to manage non visual frame objects', 'Views/DataView.py'], 'DateTimeCompanions': [0, '', 'Companions/DateTimeCompanions.py'], 'DebugClient': [0, '', 'Debugger/DebugClient.py'], 'Debugger': [0, 'Module for out-of-process debugging of Python apps', 'Debugger/Debugger.py'], 'DebuggerControls': [0, '', 'Debugger/DebuggerControls.py'], 'Designer': [0, 'View to visually design frames', 'Views/Designer.py'], 'DialogCompanions': [0, '', 'Companions/DialogCompanions.py'], 'DiffView': [0, '', 'Views/DiffView.py'], 'Editor': [0, 'Source code editor hosting models and views', 'Editor.py'], 'EditorExplorer': [0, '', 'Explorers/EditorExplorer.py'], 'EditorHelper': [0, '', 'Models/EditorHelper.py'], 'EditorModels': [0, '', 'Models/EditorModels.py'], 'EditorUtils': [0, 'Specialised ToolBar and StatusBar controls for the Editor', 'EditorUtils.py'], 'EditorViews': [0, 'Main module for View classes that work with Models', 'Views/EditorViews.py'], 'Enumerations': [0, '', 'PropEdit/Enumerations.py'], 'ErrorStack': [0, 'Various forms of error parsers', 'ErrorStack.py'], 'ErrorStackFrm': [0, '', 'ErrorStackFrm.py'], 'EventCollections': [0, '', 'Companions/EventCollections.py'], 'Explorer': [0, 'Specialised visual controls for the Explorer (Tree, list and splitter)', 'Explorers/Explorer.py'], 'ExplorerNodes': [0, '', 'Explorers/ExplorerNodes.py'], 'ExtMethDlg': [0, 'Dialog for ExternalMethods', 'ZopeLib/ExtMethDlg.py'], 'ExtraZopeCompanions.plug-in': [0, '', 'Plug-ins/ExtraZopeCompanions.plug-in.py'], 'FTPExplorer': [0, '', 'Explorers/FTPExplorer.py'], 'FileDlg': [0, 'Replacement for the standard file dialog. ', 'FileDlg.py'], 'FileExplorer': [0, '', 'Explorers/FileExplorer.py'], 'FindReplaceDlg': [0, '', 'FindReplaceDlg.py'], 'FindReplaceEngine': [0, '', 'FindReplaceEngine.py'], 'FindResults': [0, '', 'FindResults.py'], 'FlexGridGrowableDlg': [0, '', 'Companions/FlexGridGrowableDlg.py'], 'FrameCompanions': [0, '', 'Companions/FrameCompanions.py'], 'GCFrame': [0, '', 'GCFrame.py'], 'GizmoCompanions': [0, '', 'Companions/GizmoCompanions.py'], 'HTMLCyclops': [0, '', 'HTMLCyclops.py'], 'HTMLResponse': [0, '', 'HTMLResponse.py'], 'HTMLSupport': [0, '', 'Models/HTMLSupport.py'], 'Help': [0, 'Interactive help frame', 'Help.py'], 'HelpBook.plug-in': [0, '', 'Plug-ins/HelpBook.plug-in.py'], 'ImageEditor.plug-in': [0, '', 'Plug-ins/ImageEditor.plug-in.py'], 'ImageStore': [0, 'Centralised point to load images (cached/zipped/etc)', 'ImageStore.py'], 'ImageViewer': [0, '', 'ZopeLib/ImageViewer.py'], 'InProcessClient': [0, '', 'Debugger/InProcessClient.py'], 'Infofields': [0, '', 'Infofields.py'], 'InspectableViews': [0, '', 'Views/InspectableViews.py'], 'Inspector': [0, "Inspects object's constructor/properties/events/parents", 'Inspector.py'], 'InspectorEditorControls': [0, '', 'PropEdit/InspectorEditorControls.py'], 'IsolatedDebugger': [0, '', 'Debugger/IsolatedDebugger.py'], 'JavaSupport.plug-in': [0, '', 'Plug-ins/JavaSupport.plug-in.py'], 'LibCompanions': [0, '', 'Companions/LibCompanions.py'], 'ListCompanions': [0, '', 'Companions/ListCompanions.py'], 'LoginDialog': [0, '', 'ZopeLib/LoginDialog.py'], 'MaskedEditFmtCodeDlg': [0, '', 'Companions/MaskedEditFmtCodeDlg.py'], 'ModRunner': [0, 'Module that runs processes in a variety of ways', 'ModRunner.py'], 'ModuleFinder.plug-in': [0, '', 'Plug-ins/ModuleFinder.plug-in.py'], 'OGLViews': [0, '', 'Views/OGLViews.py'], 'ObjCollection': [0, '', 'Views/ObjCollection.py'], 'Palette': [1, 'Top frame which hosts the component palette and help options', 'Palette.py'], 'PaletteMapping': [0, '', 'PaletteMapping.py'], 'PaletteStore': [0, 'Storage for variables defining the palette organisation', 'PaletteStore.py'], 'PascalSupport.plug-in': [0, '', 'Plug-ins/PascalSupport.plug-in.py'], 'PathMappingDlg': [0, '', 'Debugger/PathMappingDlg.py'], 'PathsPanel': [0, '', 'Debugger/PathsPanel.py'], 'Plugins': [0, '', 'Plugins.py'], 'Preferences': [0, 'Central store of customiseable properties', 'Preferences.py'], 'PrefsExplorer': [0, '', 'Explorers/PrefsExplorer.py'], 'ProcessProgressDlg': [0, '', 'ProcessProgressDlg.py'], 'ProfileView': [0, '', 'Views/ProfileView.py'], 'PropDlg': [0, '', 'ZopeLib/PropDlg.py'], 'PropertyEditors': [0, 'Module defining property editors used in the Inspector', 'PropEdit/PropertyEditors.py'], 'PySourceView': [0, '', 'Views/PySourceView.py'], 'PyrexSupport.plug-in': [0, '', 'Plug-ins/PyrexSupport.plug-in.py'], 'PythonControllers': [0, '', 'Models/PythonControllers.py'], 'PythonEditorModels': [0, '', 'Models/PythonEditorModels.py'], 'PythonInterpreter': [0, '', 'ExternalLib/PythonInterpreter.py'], 'RTTI': [0, 'Introspection code. Run time type info', 'RTTI.py'], 'RegexEditor.plug-in': [0, '', 'Plug-ins/RegexEditor.plug-in.py'], 'RemoteClient': [0, '', 'Debugger/RemoteClient.py'], 'RemoteDialog': [0, '', 'Debugger/RemoteDialog.py'], 'RemoteServer': [0, '', 'Debugger/RemoteServer.py'], 'ResourceSupport': [0, '', 'Models/ResourceSupport.py'], 'RunCyclops': [0, '', 'RunCyclops.py'], 'SSHExplorer': [0, '', 'Explorers/SSHExplorer.py'], 'STCStyleEditor': [0, '', 'Views/STCStyleEditor.py'], 'Search': [0, '', 'Search.py'], 'SelectionTags': [0, 'Controls and objects that manage the visual selection in the Designer', 'Views/SelectionTags.py'], 'ShellEditor': [0, 'Python Interpreter Shell window', 'ShellEditor.py'], 'Signature': [0, '', 'ExternalLib/Signature.py'], 'SizerCompanions': [0, '', 'Companions/SizerCompanions.py'], 'SizersView': [0, '', 'Views/SizersView.py'], 'SourceViews': [0, '', 'Views/SourceViews.py'], 'StyledTextCtrls': [0, 'Mixin classes to use features of Scintilla', 'Views/StyledTextCtrls.py'], 'Tasks': [0, '', 'Debugger/Tasks.py'], 'Tests': [0, '', 'Tests.py'], 'UserCompanions.plug-in': [0, '', 'Plug-ins/UserCompanions.plug-in.py'], 'UtilCompanions': [0, '', 'Companions/UtilCompanions.py'], 'Utils': [0, 'General utility routines and classes', 'Utils.py'], 'WizardCompanions': [0, '', 'Companions/WizardCompanions.py'], 'XMLSupport': [0, '', 'Models/XMLSupport.py'], 'XMLView': [0, '', 'Views/XMLView.py'], 'ZipExplorer': [0, '', 'Explorers/ZipExplorer.py'], 'ZopeCompanions': [0, '', 'ZopeLib/ZopeCompanions.py'], 'ZopeEditorModels': [0, '', 'ZopeLib/ZopeEditorModels.py'], 'ZopeExplorer': [0, '', 'ZopeLib/ZopeExplorer.py'], 'ZopeFTP': [0, '', 'ZopeLib/ZopeFTP.py'], 'ZopeViews': [0, '', 'ZopeLib/ZopeViews.py'], 'methodparse': [0, 'Module responsible for parsing code inside generated methods', 'methodparse.py'], 'moduleparse': [0, 'For parsing a whole module into Module, classes and functions', 'moduleparse.py'], 'ndiff': [0, '', 'ExternalLib/ndiff.py'], 'popen2import': [0, '', 'popen2import.py'], 'prefs.gtk.rc': [0, '', 'Config/prefs.gtk.rc.py'], 'prefs.keys.rc': [0, '', 'Config/prefs.keys.rc.py'], 'prefs.mac.rc': [0, '', 'Config/prefs.mac.rc.py'], 'prefs.msw.rc': [0, '', 'Config/prefs.msw.rc.py'], 'prefs.plug-ins.rc': [0, '', 'Config/prefs.plug-ins.rc.py'], 'prefs.rc': [0, '', 'Config/prefs.rc.py'], 'reindent': [0, '', 'ExternalLib/reindent.py'], 'relpath': [0, '', 'relpath.py'], 'sourceconst': [0, 'Source generation constants', 'sourceconst.py'], 'wxNamespace': [0, '', 'wxNamespace.py'], 'wxPopen': [0, '', 'wxPopen.py'], 'wxPythonControllers': [0, '', 'Models/wxPythonControllers.py'], 'wxPythonEditorModels': [0, '', 'Models/wxPythonEditorModels.py'], 'xmlrpclib': [0, '', 'ExternalLib/xmlrpclib.py']} class BoaApp(wx.App): """ Application object, responsible for the Splash screen, applying command line switches, optional logging and creation of the main frames. """ def __init__(self): wx.App.__init__(self, False) def OnInit(self): Preferences.initScreenVars() wx.InitAllImageHandlers() wx.ToolTip.Enable(True) if Preferences.debugMode == 'release': self.SetAssertMode(wx.PYAPP_ASSERT_SUPPRESS) elif Preferences.debugMode == 'development': self.SetAssertMode(wx.PYAPP_ASSERT_EXCEPTION) conf = Utils.createAndReadConfig('Explorer') if not conf.has_section('splash'): conf.add_section('splash') modTot = 1 else: modTot = conf.getint('splash', 'modulecount') fileTot = len(eval(conf.get('editor', 'openfiles'), {})) abt = About.createSplash(None, modTot, fileTot) try: abt.Show() abt.Update() # Let the splash screen repaint wx.Yield() # Imported here to initialise core features and plug-ins import PaletteMapping print 'creating Palette' import Palette self.main = Palette.BoaFrame(None, -1, self) print 'creating Inspector' import Inspector inspector = Inspector.InspectorFrame(self.main) print 'creating Editor' import Editor editor = Editor.EditorFrame(self.main, -1, inspector, wx.Menu(), self.main.componentSB, self, self.main) self.SetTopWindow(editor) inspector.editor = editor conf.set('splash', 'modulecount', str(len(sys.modules))) try: Utils.writeConfig(conf) except IOError, err: startupErrors.append('Error writing config file: %s\nPlease ' 'ensure that the Explorer.*.cfg file is not read only.'% str(err)) if not emptyEditor: editor.restoreEditorState() self.main.initPalette(inspector, editor) ## editor.setupToolBar() import Help #print 'attaching wxPython doc strings' #Help.initWxPyDocStrs() if not Preferences.delayInitHelp: print 'initialising Help' Help.initHelp() global constricted constricted = constricted or Preferences.suBoaConstricted print 'showing main frames <<100/100>>' if constricted: editor.CenterOnScreen() inspector.CenterOnScreen() inspector.initSashes() else: self.main.Show() inspector.Show() # For some reason the splitters have to be visible on GTK before they # can be sized. inspector.initSashes() editor.Show() editor.doAfterShownActions() # Call startup files after complete editor initialisation global startupfile if Preferences.suExecPythonStartup and startupEnv: startupfile = startupEnv if editor.shell: editor.shell.execStartupScript(startupfile) finally: #time.sleep(1000) abt.Destroy() #del abt pass # Apply command line switches if doDebug and startupModules: mod = editor.openOrGotoModule(startupModules[0])[0] mod.debug() elif startupModules: for mod in startupModules: editor.openOrGotoModule(mod) editor.setupToolBar() editor.setStatus('Startup time: %5.2f' % (time.time() - t1)) Utils.showTip(self.main.editor) if Preferences.logStdStreams: sys.stderr = Utils.ErrorLoggerPF() sys.stdout = Utils.OutputLoggerPF() if Preferences.exWorkingDirectory: try: os.chdir(Preferences.exWorkingDirectory) except OSError, err: startupErrors.append('Could not set working directory from '\ 'Preferences.exWorkingDirectory :') startupErrors.append(str(err)) if startupErrors: for error in startupErrors: wx.LogError(error) wx.LogError('\nThere were errors during startup, please click "Details"') if wx.Platform == '__WXMSW__': self.tbicon =wx.TaskBarIcon() self.tbicon.SetIcon(self.main.GetIcon(), 'Boa Constructor') self.tbicon.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate) self.tbicon.Bind(wx.EVT_TASKBAR_RIGHT_UP, self.OnTaskBarMenu) self.tbicon.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE) self.tbicon.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE) self.tbicon.Bind(wx.EVT_MENU, self.OnTaskBarAbout, id=self.TBMENU_ABOUT) editor.assureRefreshed() return True [TBMENU_RESTORE, TBMENU_CLOSE, TBMENU_ABOUT] = Utils.wxNewIds(3) def OnTaskBarMenu(self, event): menu = wx.Menu() menu.Append(self.TBMENU_RESTORE, 'Restore Boa Constructor') menu.Append(self.TBMENU_CLOSE, 'Exit') menu.AppendSeparator() menu.Append(self.TBMENU_ABOUT, 'About') self.tbicon.PopupMenu(menu) menu.Destroy() def OnTaskBarActivate(self, event): if not self.main.IsShown(): self.main.editor.restore() else: self.main.restore() def OnTaskBarClose(self, event): self.main.Close() #self.ProcessIdle() def OnTaskBarAbout(self, event): self.main.editor.OnHelpAbout(event) def main(argv=None): # XXX Custom installations, should distutil libs be used for this ? # XXX Binary test is no longer valid, maybe type of __import__ function # Only install if it's not a 'binary' distribution if Preferences.installBCRTL and hasattr(wx, '__file__'): join, dirname = os.path.join, os.path.dirname wxPythonPath = dirname(wx.__file__) wxPythonLibPath = join(dirname(wx.__file__), 'lib') ##pythonLibPath = dirname(wx.PythonPath) try: # Install/update run time libs if necessary Utils.updateDir(join(Preferences.pyPath, 'bcrtl'), join(wxPythonLibPath, 'bcrtl')) except Exception, error: startupErrors.extend(['Error while installing Run Time Libs:', ' '+str(error), '\nMake sure you have sufficient rights to copy these files, and that ', 'the files are not read only. You may turn off this attempted ', 'installation in prefs.rc.py : installBCRTL']) if argv is not None: global doDebug, startupfile, startupModules, constricted, emptyEditor, \ doDebugSvr, blockSocketServer doDebug, startupfile, startupModules, constricted, emptyEditor, \ doDebugSvr, blockSocketServer, opts, args = processArgs(argv) try: app = BoaApp() except Exception, error: wx.MessageBox(str(error), 'Error on startup') raise app.MainLoop() # Clean up (less warnings) if hasattr(app, 'tbicon'): del app.tbicon if not hasattr(sys, 'boa_debugger'): if Preferences.logStdStreams: sys.stderr = sys.__stderr__ sys.stdout = sys.__stdout__ Preferences.cleanup() del app if __name__ == '__main__': main()