#! /usr/bin/env python # Part of the A-A-P GUI IDE: The main function. # Copyright (C) 2002-2003 Stichting NLnet Labs # Permission to copy and use this file is specified in the file COPYING. # If this file is missing you can find it here: http://www.a-a-p.org/COPYING # Main Python code that starts Agide import sys import os.path # We need to know the location of our modules. Need to use an absolute # path, we might change directories. try: rootdir = os.path.dirname(os.path.realpath(sys.argv[0])) except: # Doesn't have os.path.realpath(), it's new in Python 2.2 # Try using our copy of it. try: from Realpath import myrealpath rootdir = os.path.dirname(myrealpath(sys.argv[0])) except: # Still not working? Fall back to using abspath(). rootdir = os.path.dirname(os.path.abspath(sys.argv[0])) # When started with a relative path and changing directories we still need # to be able to find our modules. sys.path.append(rootdir) # Search for Recipe Executive modules in a specific directory. execdir = os.path.join(os.path.dirname(rootdir), "Exec") # Try matching the version number. If there are no matches the # ImportError below will occur. import glob dirlist = glob.glob(execdir + "-[0-9].[0-9]*") if dirlist: # if there are multiple matches use the latest version. dirlist.sort() execdir = dirlist[-1] if os.path.isdir(execdir): sys.path.append(execdir) # Search for Activity classes in a subdirectory. sys.path.append(os.path.join(rootdir, "Activities")) # Search for Tool classes in a subdirectory. sys.path.append(os.path.join(rootdir, "Tools")) try: from Util import * except ImportError: print "Can't load Aap, please install it first." sys.exit(1) import Tool import Navigator import Config # message translation def _(x): return Tool._gettext(x) # # The following is a top-down sequence of the items in Agide. # def agideMain(activity = None): """Create the toplevel AIDE object and start the GUI.""" # Check that the required version of Aap is available. wrongversion = 0 try: import AapVersion except StandardError: wrongversion = 1 if not wrongversion: required = 0.905 if float(AapVersion.version_string) < required: wrongversion = 2 if wrongversion: print "The version of Aap is too old for this version of Agide." if wrongversion == 2: print ("You are using Aap %s while %s is required." % (AapVersion.version_string, str(required))) print "Please get a newer version of Aap." # TODO: automatically upgrade Aap? return # Postpone importing wxPython until here, so that "agide --version" doesn't # require an X server (merely importing wxPython triggers making the # connection). try: from wxPython.wx import wxNewId except ImportError, e: print "Can't load wxPython, perhaps you need to install it first?" print "Error: ", e sys.exit(1) import GUItop # Create the toplevel data structures. topmodel = AIDE() # Read the configuration file (with recently used files) Config.readConfig(topmodel) # Setup for message translation. Tool.init_gettext(topmodel) # XXX here we could chose the GUI to be used. # Create the GUI application, pass on the model. topmodel.app = GUItop.AgideApp(0, topmodel) # Open an activity passed as an argument. if activity: topmodel.addActyByName(activity) # Run until we die. topmodel.app.MainLoop() # Write the configuration file (with changes) Config.writeConfig(topmodel) class AIDE: """The toplevel class for all data in an A-A-P IDE.""" def __init__(self): import Activity # Create the toplevel data structures. # - The list of open Activities self.actylist = Activity.ActyList() # - The list of running Tools self.toollist = Tool.ToolList() # - The list of opened Nodes self.nodelist = Navigator.NodeList() # - The GUI application self.app = None # - The toplevel view (Navigation window) self.view = None # - The top directory, where Tools and Activities are found. global rootdir self.rootdir = rootdir # Flag that indicates we are trying to exit: don't bring an activity or # item to the foreground. self.shutting_down = 0 # Dictionary which holds values from agide.cnf self.confdict = {} # File name to read configuration from, see Config.py. self.configfname = None def shutdown(self, forced): """Attempt to shutdown. When something doesn't want to shutdown (unsaved changes) don't exit, unless "forced" is non-zero.""" self.shutting_down = 1 if (self.actylist.shutdown() and Tool.shutdown_no_acty()) or forced: ok = 1 else: ok = 0 self.shutting_down = 0 if not ok: self.actylist.fixActy() return ok def consoleMsg(self, msg): """Display a message in the console window.""" # Since stdout is redirected to the console window when possible, we # can use "print". Raise the console window if it exiss. # XXX should we add a log file here? print msg if self.view: self.view.raiseConsole() def doDialog(self, msg, choices, default): """Show a dialog. "msg" is the text for the dialog. "choices" is the list of alternatives. "default" is de index in choices[] for the default choice. Returns the entry in "choices" that was selected or "Cancel" when the dialog was cancelled.""" if self.view: return self.view.doDialog(msg, choices, default) # Can't show a dialog, return the default. return choices[default] def addActyByName(self, name): """Add a new activity from a file, selecting the Activity class by its name.""" # Find an activity that can be used. Import the class if found, # otherwise fall back to the base class. import Activity classname = Activity.name2class(name, self) if classname: exec "import " + classname else: classname = "Activity" # Create the new Activity and open it. act = eval(classname + "." + classname + "(name, self)") act.open() # Add the Activity to the list of activies. self.actylist.addActy(act) # Bring the new Activity to the foreground. act.foreground() def newActy(self, cl): """Create a new activity by class name "cl".""" exec "import " + cl # Create the new Activity and open it. act = eval(cl + ".create(self)") if act: # Add the Activity to the list of activies. self.actylist.addActy(act) # Bring the new Activity to the foreground. act.foreground() def delActy(self, acty): """Delete Activity "acty". It has already been closed by the caller.""" self.actylist.remove(acty) def postCall(self, function, *args, **kwargs): """Invoked from a different thread: Call "function(args)" from the main thread. Used to handle events synchronously.""" # Use a wxPython event to handle this. apply(self.view.postCall, (function,) + args, kwargs) # The main function. def main(): if len(sys.argv) >= 2 and sys.argv[1] == "--version": # "agide --version": print version info and exit. import AgideVersion import AapVersion print "Agide version %s, %s" % (AgideVersion.version_string, AgideVersion.version_date) print "Using Aap version %s, %s" % (AapVersion.version_string, AapVersion.version_date) sys.exit(0) if len(sys.argv) >= 2 and sys.argv[1] == "--help": # "agide --help": print help and exit. print "Agide: A-A-P GUI IDE" print "agide Open main window" print "agide activity Open main window and start 'activity'" print "agide --version Print version info and exit" print "agide --help Print this help and exit" sys.exit(0) if len(sys.argv) == 2: # "agide name": open activity "name" right away. agideMain(sys.argv[1]) else: # Just open the main window. agideMain() # When executed directly, call the main function. if __name__ == '__main__': main() # vim: set sw=4 et sts=4 tw=79 fo+=l: