/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.biolegato.main; import java.awt.Desktop; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.regex.Pattern; import javax.imageio.ImageIO; import javax.swing.Action; import javax.swing.ImageIcon; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JScrollPane; import javax.swing.JTextPane; import org.biopcd.parser.CommandThread; import org.biopcd.parser.PCD; import org.biopcd.parser.PCDObject; import org.biopcd.parser.RunWindow; /** * The main BioLegato class. * This class contains all of the basic code to launch BioLegato. ** * @author Graham Alvare * @author Brian Fristensky */ public class BLMain { /** * The width to display the icons in BioLegato menus */ private static final int ICONW = 16; /** * The height to display the icons in BioLegato menus */ private static final int ICONH = 16; /** * This constant is set to the path of where biolegato was run * The value of this constant determined at runtime. */ public static final String CURRENT_DIR = (String) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { try { return System.getProperty("user.dir"); } catch (Exception ex) { ex.printStackTrace(System.err); return ""; } } } ); /** * Stores all of the plugins loaded into BioLegato */ private static Map plugins = new HashMap(); /** * Stores information regarding the usage of the debug command * NOTE: This should always be accessed using BLMain.debug */ public static boolean debug = false; //---------------------------- BioLegato METHODS ----------------------------// /** *

Starts BioLegato from the command line.

* *

This method is split into the following sections:

*
    *
  1. Declare function variables.
  2. *
  3. Load BioLegato's properties.
  4. *
  5. Load plug-ins.
  6. *
  7. Process command-line arguments.
  8. *
  9. Correct DEBUG MODE status
  10. *
  11. Start the BioLegato interface * (calls 'main' with the canvas to load)
  12. *
*

Note, the above list is NOT the same as the list for * main (String[] args).

*

This method contains code necessary for enabling Turtle SHELL.

** * @param canvas the canvas class to load BioLegato with. * @param args the command line arguments for BioLegato. */ public static void main(Class canvas, String[] args) { ///////////////////////////// //*************************// //* 1. FUNCTION VARIABLES *// //*************************// ///////////////////////////// // RESERVED (general purpose - inner scoped) // fileIn // currentCanvas Properties propImport = new Properties(); List dataAdd = new LinkedList(); String[] propertiesFiles = null; boolean serverMode = false; boolean pipeInput = false; //////////////////////////////////// //********************************// //* 2. PROPERTIES INITIALIZATION *// //********************************// //////////////////////////////////// // ------------------ UNCOMMENT BELOW FOR TURTLESHELL ------------------ //Turtle.localenv.put("PWD", CURRENT_DIR); //Turtle.localenv.put("BL_DIR", envreplace("$BL_DIR")); //Turtle.localenv.put("BL_HOME", CURRENT_DIR); // ------------------ UNCOMMENT ABOVE FOR TURTLESHELL ------------------ //////////////////////////////////////////////////////////////////////// // Generate a list of properties files to read // // This list is obtained from the $BL_PROPERTIES environment variable // //////////////////////////////////////////////////////////////////////// // The $BL_PROPERTIES environment variable is treated as a list of // properties files for BioLegato. Each list entry is seperated by // File.separator (':' in UNIX, ';' in Windows). The files are read // in string order from left-to-right. if (System.getenv("BL_PROPERTIES") != null) { propertiesFiles = toPathList(System.getenv("BL_PROPERTIES")); } else { // If $BL_PROPERTIES is not set, then the default properties // file location is: "$BL_DIR/.blproperties". propertiesFiles = new String[] { "$BL_DIR" + File.separator + ".blproperties" }; } //////////////////////////////////////////////////////////////////////// // Load the default properties JAR file. // //////////////////////////////////////////////////////////////////////// // This coad reads in the default properties from the JAR file. This // ensures that all properties have default values. // Reading is done with a try-catch block to ensure that BioLegato // will NOT start if there are any errors reading the default // properties file. The default properties file is contained within // the root directory of BioLegato's JAR file. try { // Read the JAR's default properties located // at /default.properties, within the JAR file. propImport.load(DataCanvas.class.getResourceAsStream( "/default.properties")); } catch (IOException ioe) { System.err.println("FATAL ERROR - CORRUPT JAR FILE"); ioe.printStackTrace(System.err); System.exit(1); } //////////////////////////////////////////////////////////////////////// // Read all of the properties //////////////////////////////////////////////////////////////////////// // Read all of the additional properties files // (specified by the $BL_PROPERTIES environment variable). for (String file : propertiesFiles) { File propertiesFileTemp = new File(file); // If the properties path specified is a directory, then load the // .blproperties file contained within that directory. if (propertiesFileTemp.isDirectory()) { propertiesFileTemp = new File(file + File.separator + ".blproperties"); } // If the path specified is a file, then load the properties from // that file. if (propertiesFileTemp.exists() && propertiesFileTemp.canRead() && propertiesFileTemp.isFile()) { try { propImport.load(new FileInputStream(propertiesFileTemp)); } catch (Throwable e) { e.printStackTrace(System.err); } } } propertiesFiles = null; //////////////////////// //********************// //* 3. LOAD PLUG-INS *// //********************// //////////////////////// for (String pluginDir : toPathList(propImport.getProperty("plugins"))) { // load the plugins and file formats PluginLoader.loadPlugins(plugins, pluginDir); } ///////////////////////////////////////// //*************************************// //* 4. PROCESS COMMAND-LINE ARGUMENTS *// //*************************************// ///////////////////////////////////////// // ensure that args is not null if (args != null) { // itterate through the command arguments for (String rawarg : args) { try { // discard null arguments if (rawarg != null) { File fileIn = null; // Create a new file object. This file object is used // to test if the argument specified (rawarg) is a valid // system file. If not, then we must do parameter // parsing. fileIn = new File(rawarg); // if the argument is a file name then read the file; // otherwise, parse the argument if (fileIn != null && fileIn.exists() && fileIn.isFile() && fileIn.canRead()) { dataAdd.add(fileIn); } else if (rawarg.startsWith("/") || rawarg.startsWith( "-")) { // copy the command line argument String value = null; String argument = rawarg; // trim the argument if (argument.startsWith("--") && argument.length() > 2) { // trim -- from the argument name argument = argument.substring(2); } else if ((argument.startsWith("/") || argument.startsWith("-")) && argument.length() > 1) { // trim - or / from the argument name argument = argument.substring(1); } // If there is an equals '=' sign then the argument // has a value. Set the value variable to the // arguments' value for further parsing. if (argument.indexOf('=') > 0) { value = argument.substring( argument.indexOf('=') + 1); argument = argument.substring(0, argument.indexOf('=')); } // make the argument lower case for better parsing argument = argument.toLowerCase().trim(); ////////////////////////////////////// //**********************************// //* PROCESS COMMAND LINE ARGUMENTS *// //**********************************// ////////////////////////////////////// if ("help".equals(argument) || "h".equals(argument) || "?".equals(argument)) { //////////// //********// //* HELP *// //********// //////////// // show BioLegato's usage System.out.println( "Usage: biolegato [options] [files]\n" + "Use --optionlist to see a detailed" + " list of options\n" + "Use --manpage to see BioLegato's" + " manpage"); System.exit(0); } else if ("optionlist".equals(argument)) { /////////////////// //***************// //* OPTION LIST *// //***************// /////////////////// // Show BioLegato's list of options: // i.e., write the file "optionlist.txt" to // System.in -- "optionlist.txt" is located // within the root (/) of the jar file new StreamCopier(StreamCopier.DEFAULT_BUFF_SIZE, DataCanvas.class.getResourceAsStream( "/optionlist.txt"), System.out).run(); System.exit(0); } else if ("manpage".equals(argument) || "man".equals(argument)) { /////////////// //***********// //* MANPAGE *// //***********// /////////////// // Show BioLegato's manpage: // i.e., write the file "manpage.txt" to // System.in -- "manpage.txt" is located // within the root (/) of the jar file new StreamCopier(StreamCopier.DEFAULT_BUFF_SIZE, DataCanvas.class.getResourceAsStream( "/manpage.txt"), System.out).run(); System.exit(0); } else if (("exec-properties".equals(argument) || "ep".equals(argument)) && value != null) { /////////////////////// //*******************// //* EXEC PROPERTIES *// //*******************// /////////////////////// // Executes a command specified (after an equals // sign), and read the standard output from this // command as if it were a properties file. Process p = Runtime.getRuntime().exec( BLMain.envreplace(value).split("\\s")); p.getOutputStream().close(); propImport.load(p.getInputStream()); } else if ("version".equals(argument) || "v".equals(argument)) { /////////////// //***********// //* VERSION *// //***********// /////////////// // Show BioLegato's version number. // NOTE: 1.1.2 is replaced with the // version number of BioLegato by the ant // build script. System.out.println("BioLegato v1.1.2"); System.exit(0); } else if ("debug".equals(argument)) { ///////////// //*********// //* DEBUG *// //*********// ///////////// // Force/enable DEBUG MODE. debug = true; } else if ("plugins".equals(argument)) { /////////////// //***********// //* PLUGINS *// //***********// /////////////// // Show all of the plugins loaded successfully // into BioLegato. System.out.println( "***********\n" + "* PLUGINS *\n" + "***********"); System.out.println("(Current plugins path: " + propImport.getProperty("plugins") + ")\n" + "-- listing plugins loaded --"); String[] pluginList = plugins.keySet().toArray( new String[0]); for (String pluginName : pluginList) { System.out.append("Plugin: " ).append(pluginName).append("\n"); } System.out.flush(); System.out.println("-- end of plugin list --"); } else if ("pipe".equals(argument)) { //////////// //********// //* PIPE *// //********// //////////// // Pipe input from System.in into the canvas pipeInput = true; } else if ("server".equals(argument)) { ////////////// //**********// //* SERVER *// //**********// ////////////// // Starts BioLegato as a PCD menus server for // other BioLegato instances. // (NOT YET IMPLEMENTED) serverMode = true; } else { System.err.println("Unknown argument: " + rawarg); } } } } catch (Throwable th) { System.err.println("Error processing argument: " + rawarg); th.printStackTrace(System.err); } } } //////////////////////////////////// //********************************// //* 5. CORRECT DEBUG MODE STATUS *// //********************************// //////////////////////////////////// // Correctly set the debug parameter after all command-line arguments // are specified. The debug variable is set after processing the // enture command-line, because additional properties files and a // command-line specific debug-switch can both alter whether the debug // parameter should be turned on. Please note that the command-line // "debug" switch takes precedence over any properties file value for // debug mode. if ("true".equalsIgnoreCase(propImport.getProperty("debug")) || (System.getenv("BL_DEBUG") != null && !"".equals(System.getenv("BL_DEBUG").trim()) && !"false".equalsIgnoreCase(System.getenv("debug")))) { debug = true; } // If BioLegato is in DEBUG MODE, then display that the // command-line arguments were read successfully. if (debug) { System.err.println("Command line arguments read successfully"); // Also, display all of the properties values loaded into BioLegato. System.err.println( "**************\n" + "* PROPERTIES *\n" + "**************"); propImport.list(System.err); } //////////////////////////////////// //********************************// //* 6. START BIOLEGATO INTERFACE *// //********************************// //////////////////////////////////// if (!serverMode && canvas != null) { main(canvas, propImport, dataAdd, pipeInput); } else { // TODO: implement server mode for BioLegato try { //Naming.rebind ("BioLegato", new BLServer ()); System.out.println ("BioLegato Server is ready."); } catch (Exception e) { System.out.println ("BioLegato Server failed: " + e); } } } //------------------------------ END OF METHOD ------------------------------// /** *

Starts a new BioLegato instance (i.e. loads a canvas).

* *

This method is split into the following sections:

*
    *
  1. Initialize the canvas.
  2. *
  3. Read initial canvas data -- read any files (such as GenBANK or * FASTA DNA/Protein sequences) to initialize the canvas with).
  4. *
  5. Add the initial BioLegato menu headings (e.g. File, Edit).
  6. *
  7. Read in the custom PCD menus.
  8. *
  9. Add the default trailing menu items.
  10. *
  11. DONE: Display the new BioLegato instance.
  12. *
** * @param canvasClass the DataCanvas to load BioLegato with. */ public static void main(Class canvasClass, Properties propImport, List dataAdd, boolean pipeInput) { //////////////////////////////// //****************************// //* 1. INITIALIZE THE CANVAS *// //****************************// //////////////////////////////// // Declare canvas variable DataCanvas canvas = null; try { canvas = (DataCanvas) canvasClass.getConstructor(new Class[]{ Map.class}).newInstance(new Object[]{propImport}); /////////////////////////////////// //*******************************// //* 2. READ INITIAL CANVAS DATA *// //*******************************// /////////////////////////////////// // get the input for the canvas from system.in if (pipeInput) { try { canvas.readFile("", new InputStreamReader(System.in), false,false); } catch (IOException ioe) { System.out.println("Failed to read System.in"); ioe.printStackTrace(System.err); } } for (File file : dataAdd) { try { if (file != null && file.exists() && file.isFile() && file.length() > 0) { canvas.readFile("", new FileReader(file), false,false); } } catch (FileNotFoundException ex) { ex.printStackTrace(System.err); } catch (IOException ex) { ex.printStackTrace(System.err); } } /////////////////////////////////////// //***********************************// //* 3. READ IN THE CUSTOM PCD MENUS *// //***********************************// /////////////////////////////////////// // load all PCD menu files loadPCD(canvas); // load any Java class "Plugin menus" for (String filename : toPathList(canvas.getProperty("pcd.menus.path"))) { loadPluginMenus(canvas, new File(filename)); } ////////////////////////////////////////////// //******************************************// //* 4. ADD THE DEFAULT TRAILING MENU ITEMS *// //******************************************// ////////////////////////////////////////////// // Add the "Exit" button canvas.addMenuHeading("File").add(canvas.EXIT_MENUITEM); // Add the "About" button canvas.addMenuHeading("Help").add(canvas.ABOUT_MENUITEM); /////////////////////////////////////////////////// //***********************************************// //* 5. DONE: DISPLAY THE NEW BIOLEGATO INSTANCE *// //***********************************************// /////////////////////////////////////////////////// canvas.createJFrame(); } catch (Exception ex) { ex.printStackTrace(System.err); } } //------------------------------ END OF METHOD ------------------------------// /** *

For each instance of $XXX (where XXX is the name of an environment * variable), this function replaces $XXX with its current value (which * is obtained from the environment via. System.getenv).

* *

This function provides functionality similar to BASH (i.e. replaces * $XXX with the value of XXX in the environment.)

* *

NOTE: there are some environment variables intrinsic to BioLegato. *
These variables are: *

$BL_DIR
the directory which contains BioLegato
*
$BL_HOME
the directory where the user launched BioLegato * (this is the only intrinsic variable, which the * environment can override -- i.e. if $BL_HOME is * set in the System's environment, the System * environment value will take precedence).
*
$HOME
the user's home directory
*

** * @param original the string to modify. * @return the modified string. */ public static String envreplace(final String original) { // TRANSITION WRAPPING (for future JApplet support!) return (String) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { try { int start = 0; int end = -1; String replace = null; String variable = ""; String change = original; /** * This constant is used to improve the legibility of * the code which figures out the PROGRAM_DIR * properties. DO NOT OTHERWISE USE THIS CONSTANT, * AS IT MAY DISAPPEAR IN FUTURE VERSIONS! */ final File EXE_DIR_DONT_USE = new File( DataCanvas.class.getProtectionDomain( ).getCodeSource().getLocation().getPath()); /** * This constant is set to the path of BioLegato.jar * The value of this constant determined at runtime. */ final String PROGRAM_DIR = ( EXE_DIR_DONT_USE.isDirectory() ? EXE_DIR_DONT_USE.getPath() : EXE_DIR_DONT_USE.getParentFile().getPath() ); /** * Stores the user's home directory * TRANSITION WRAPPING (for future JApplet support!) */ final String HOME_DIR = (String) AccessController.doPrivileged( new PrivilegedAction() { public Object run() { try { return System.getProperty("user.home"); } catch (Throwable th) { th.printStackTrace(System.err); return CURRENT_DIR; } } } ); // Protect against a null input string if (change != null) { ///////////////////////////////////////// // Replace each variable in the string // ///////////////////////////////////////// // This is done with the following algorithm: // INITIALIZE: // - start the algorithm with 'start' = 0 // // BEGIN LOOP: // - find the next $ symbol from 'start' // - use a for loop to find how long the // environment variable name is, set // this position to 'end' // - search the environment for the variable: // - if the variable is BL_DIR or HOME // then use the intrinsic values // - if the variable is BL_HOME, then only // use the intrinsic value, if it has no // set value in the system environment // - replace the $ variable instacnce // - if the variable does not exist in // the environment, or instrinsically, // then skip it and just increment // 'start' (i.e. do not replace); // however, DO NOT RELY ON THIS, because // if the value is set to "", then the // variable WILL be replaced with ""! // END LOOP ///////////////////////////////////////// while ((start = change.indexOf('$', start)) >= start && start > -1) { for (end = start + 1; end < change.length() && (change.charAt(end) == '_' || Character.isLetterOrDigit( change.charAt(end))); end++) { /* ITTERATE */ } // get the information to perform the string // replacement. variable = change.substring(start + 1, end); replace = System.getenv(variable); // ensure BL_DIR is set properly. if (variable.equalsIgnoreCase("BL_DIR")) { replace = PROGRAM_DIR; } // ensure HOME is set properly. if (variable.equalsIgnoreCase("HOME")) { replace = HOME_DIR; } // ensure BL_HOME is set properly. if (variable.equalsIgnoreCase("BL_HOME")) { if (replace == null || "".equals( replace.trim()) || !new File(replace).exists()) { replace = CURRENT_DIR; } else { replace = new File( replace).getAbsolutePath(); } } // perform the string replacement. if (replace != null) { change = change.substring(0, start) + replace + change.substring(end); } else { // if there is no replacement, just skip // this instance of $VARIABLE start++; } } } // return the replaced string return change; } catch (Throwable th) { th.printStackTrace(System.err); return original; } } }); } //------------------------------ END OF METHOD ------------------------------// /** *

Separates a string into a list of substrings, using File.pathSeparator * as the delimiter. This allows the user to specify multiple paths in a * string.

* *

This function does NOT evaluates any environment variables within * the original or split strings.

** * @param searchstring the string to split into multiple file paths. * @return a list of file paths contained within the input string. */ public static String[] toPathList (String searchstring) { // Allow for escaping the File.pathSeparator character in each path String[] pathlist = searchstring.split("(?Recursively load all of the Plugin menus (within a given path) * into a BioLegato canvas. Note that Plugin menus are Java classes which * conform to the following specification:

* *
    *
  1. extend the JMenuItem, JMenu, or Action class
    *
    NOTE: JMenu objects can only be read from .jar files, while * JMenuItem and Action can only be read from .class files! *
  2. *
  3. has one constructor which accepts a Datacanvas as its parameter
  4. *
  5. the class is contained within a .class or .jar file
  6. *
*/ public static void loadPluginMenus(DataCanvas canvas, File path) { String tpath = path.getAbsolutePath().toLowerCase(); // Ensure that the path is valid. if (path.exists() && path.canRead()) { // RECURSION if-statement: 1 recursive case and 2 base cases if (path.isDirectory()) { // RECURSIVE CASE: if the parameter 'path' is a directory, call // loadPluginMenus on each subdirectory/file within 'path' for (File subdir : path.listFiles()) { loadPluginMenus(canvas, subdir); } } else if (tpath.endsWith(".class")) { // BASE CASE #1/2: if the file is a class file, try loading it. try { /* * Handles reading in class files instead of PCD * (this feature can be enabled from the properties file * for BioLegato). */ // The DataCanvas class object. Used to find the proper // constructor method for the class represented by // the plugin. final Class [] canvasClass = new Class [] { DataCanvas.class }; // The current canvas. Used for calling the plugin class's // constructor method (after found using canvasClass). final Object[] canvasObject = new Object[] { canvas }; // The plugin hash object. Used for indexing plugins. Map pluginHash = new HashMap(); // Load the classes from the .class file into 'pluginHash' PluginLoader.loadClasses(pluginHash, path.getParentFile( ).toURI().toURL(), path.getName().substring(0, path.getName().length() - 6)); // Parse each class in 'pluginHash'; if it is a JMenuItem, // or an Action, then try loading it as a BioLegato menu. for (PluginWrapper plugin : pluginHash.values()) { // SKIP all classes which contain a $ in their names if (!plugin.getName().contains("$")) { if (plugin.isA(JMenuItem.class)) { // handle JMenuItem objects try { // Create a new JMenuBar from the plugin // class. canvas.getJMenuBar().add((JMenuItem) plugin.create(canvasClass, canvasObject)); } catch (Throwable th) { // Handle failure creating the JMenuBar. System.err.println("BioPCD: error loading" + " the plugin menu: " + plugin.getName()); th.printStackTrace(System.err); } } else if (plugin.isA(Action.class)) { // handle Action objects try { // Create a new JMenuItem from the plugin // class. canvas.getJMenuBar().add(new JMenuItem( (Action) plugin.create(canvasClass, canvasObject))); } catch (Throwable th) { // Handle failure creating the JMenuItem. System.err.println("BioPCD: error loading" + " the plugin menu: " + plugin.getName()); th.printStackTrace(System.err); } } } } } catch (Throwable th) { // Handle failure reading the plugin. System.err.println("BioPCD: error loading the class: " + path); th.printStackTrace(System.err); } } else if (tpath.endsWith(".jar")) { // BASE CASE #2/2: if the file is a JAR file, load each class // within the JAR file. try { /* * Handles reading in class files instead of PCD * (this feature can be enabled from the properties * file for BioLegato). */ Map pluginHash = new HashMap(); // Load the classes from the .jar file into 'pluginHash' PluginLoader.loadJar(pluginHash, path); // Parse each class in 'pluginHash'; if it is a JMenu // class, then try loading it as a BioLegato menu. for (PluginWrapper plugin : pluginHash.values()) { if (plugin.isA(JMenu.class)) { try { canvas.getJMenuBar().add( (JMenu) plugin.create()); } catch (Throwable th) { System.err.println("BioPCD: error loading the" + " plugin: " + plugin.getName()); th.printStackTrace(System.err); } } } } catch (Throwable th) { System.err.println("BioPCD: error loading the jar file: " + path); th.printStackTrace(System.err); } } } } //------------------------------ END OF METHOD ------------------------------// /** * Loads the entire PCD menu structure into BioLegato */ public static void loadPCD (DataCanvas canvas) { // Stores the PCD menu items parsed Map> result = new LinkedHashMap>(); // Set PCD to only be in DEBUG MODE if BioLegato is also in DEBUG MODE PCD.debug = debug; // Load every PCD file, recursively, from BioLegato's "pcd.menus.path" // configuration parameter. This parameter supports multiple paths, // by using BLMain.toPathList. With each iteration, path is set to // the one of the directories in pcd.menus.path. for (String path : BLMain.toPathList(canvas.getProperty("pcd.menus.path"))) { PCD.loadPCDPath(new File(path), result, canvas, canvas.getJFrame()); } // If the "pcd.exec" configuration parameter is set, then run the // command specified by "pcd.exec" and pipe its output to the PCD parser if (!"".equals(canvas.getProperty("pcd.exec"))) { try { // Execute the program and extract its standard ouptut Process p = Runtime.getRuntime().exec(BLMain.envreplace( canvas.getProperty("pcd.exec")).split("\\s")); p.getOutputStream().close(); // Pipe the output into the PCD parser. File home = new File(BLMain.envreplace("$BL_HOME")); PCD parser = new PCD(new InputStreamReader(p.getInputStream())); new Thread(new StreamCopier(StreamCopier.DEFAULT_BUFF_SIZE, p.getErrorStream(), System.err)).start(); // Parse the menu items parser.parseFullMenu(result, 0, home, canvas, canvas.getJFrame()); } catch (Throwable th) { th.printStackTrace(System.err); } } // Add every menu item parsed by the PCD parser to BioLegato's menu bar for (Map.Entry> entry : result.entrySet()) { for (PCDObject pcdo : entry.getValue().values()) { // Generate the JMenuItem object for the menu JMenuItem jmiresult = generateJMenuItem(pcdo, canvas.getJFrame()); // Add the menu to the menu bar canvas.addMenuHeading(entry.getKey()).add(jmiresult); } } } //------------------------------ END OF METHOD ------------------------------// /** *

Generates JMenuItems for PCD objects read in by the parser.

* *

This method ensures the following:

*
    *
  1. only PCD menus supported on the current system will be loaded * (e.g. if you run BioLegato, as part of BIRCH, on a Mac OS X * machine, the BIRCH PCD menu directory will contain BOTH * Linux and OS X menus, but BioLegato will only load those * menus compatible with OS X -- ignoring those which only * work on Linux, or other operating systems).
  2. * *
  3. PCD menus can have program icons
    * NOTE: program icons can use relative or absolute paths, * with OR without environment variables. The environment * variables are handled by 'envreplace', thus all BioLegato * intrinsic variables (e.g. $BL_DIR) are available for use! * *
  4. * *
  5. PCD menus can have tooltips
  6. * *
  7. PCD menus are imported as either: *
      *
    1. CommandThread objects
      do not require the user * to set parameters to run the program
    2. *
    3. RunWindow objects
      require the user to set * parameters
    4. *
    *
  8. *
** * @param pcdo the PCD object to generate the JMenuItem for * @param parent the parent JFrame (for modality purposes) * @return returns the corresponding JMenuItem object for the PCD code. */ private static JMenuItem generateJMenuItem(PCDObject pcdo, JFrame parent) { /* A file object to ensure a proper icon file path exists */ File imageFile = null; /* The icon file name for displaying on the menu */ ImageIcon imageIcon = null; /* The icon data for displaying in the parameters window * for the menu item*/ BufferedImage image = null; /* The resulting menu item that was parsed from the file */ JMenuItem jmiresult = null; ////////////////////////////////////////////////////////////////////// // 1. Ensure that only PCD menus supported by the current system // // (and computer architechture) are loaded into BioLegato. // ////////////////////////////////////////////////////////////////////// if (pcdo.isSystemSupported()) { /////////////////////////////////////////// // 2. Load any applicable program icons. // /////////////////////////////////////////// try { // check if we are loading a program icon if (pcdo.icon != null && !"".equals(pcdo.icon)) { // Handle environment variables in the path String imagePath = BLMain.envreplace(pcdo.icon); ///////////////////////////// // Handle image file paths // ///////////////////////////// // This code block will branch based on whether the path // specified for the program icon's image file is relative // or absolute. This is because Java's File class provides // at least two constructors -- one for relative paths and // one for absolute paths. To avoid any possible // under-the-hood API problems, BioLegato detects which // constructor to use, and used the appropriate constructor. ///////////////////////////// if (imagePath.startsWith("/")) { imageFile = new File(imagePath); } else { imageFile = new File(imagePath, imagePath); } // Load the program icon's image file into a Java ImageIcon // object, for use with the program's final JMenuItem if (imageFile != null && imageFile.exists() && imageFile.canRead() && imageFile.isFile()) { BufferedImage fileImage = ImageIO.read(imageFile); // image load code adapted from: // http://stackoverflow.com/questions/6916693/jmenuitem-imageicon-too-big if (fileImage != null) { image = new BufferedImage(ICONW, ICONH, BufferedImage.TYPE_INT_RGB); image.getGraphics().drawImage(fileImage, 0, 0, ICONW, ICONH, null); imageIcon = new ImageIcon(image); } } } } catch (Exception e) { System.err.println("BioPCD: Invalid image format: " + pcdo.icon); imageIcon = null; } // If an image icon was loaded successfully, then we add it to the // program's JMenuItem. Otherwise, we do not add any image to the // program's JMenuItem object. if (imageIcon != null) { jmiresult = new JMenuItem(pcdo.name, imageIcon); } else { jmiresult = new JMenuItem(pcdo.name); } // If a tooltip was specified in the PCD code, // add it to the program's JMenuItem object! if (pcdo.tooltip != null && !"".equals(pcdo.tooltip)) { jmiresult.setToolTipText(pcdo.tooltip); } // Determine whether to create a new window on clicking the menu // item or directly run the command specified in the PCD file's // exec parameter. // // This is determined by wheter the exec parameter is specified // in the PCD file! if (pcdo.exec != null) { jmiresult.addActionListener(new CommandThread(pcdo.exec, pcdo.widgetList)); } else { jmiresult.addActionListener(new RunWindow(pcdo.name, pcdo.widgetList, parent, image)); } } else { System.out.println("System not supported"); } return jmiresult; } //------------------------------ END OF METHOD ------------------------------// /** * Opens an HTML web browser in BioLegato ** * WARNING: if the function fails, null will be returned instead * of an object. ** * @param dest the destination URL to display in the web browser. */ public void browser (URL dest) { Desktop desktop = Desktop.getDesktop(); // if Java 1.7 is installed, and desktop.browse is supported if(desktop.isSupported( java.awt.Desktop.Action.BROWSE ) ) { try { desktop.browse( dest.toURI() ); } catch ( Exception e ) { System.err.println( e.getMessage() ); } } else { // default to BioLegato's VERY simple HTML browser JFrame dialog = new JFrame("URL: " + dest); JTextPane webpane; JScrollPane browser = null; if (dest != null) { try { webpane = new JTextPane(); webpane.setContentType("text/html"); webpane.setPage(dest); webpane.setEditable(false); browser = new JScrollPane(webpane, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); } catch (IOException ioe) { ioe.printStackTrace(System.err); } } dialog.add(browser); dialog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); dialog.setVisible(true); dialog.pack(); } } }