package gdsc.smlm.ij.plugins; import ij.Executer; import ij.IJ; import ij.Prefs; import ij.WindowManager; import ij.gui.GUI; import ij.plugin.frame.PlugInFrame; import java.awt.Button; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Panel; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowEvent; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import gdsc.core.utils.UnicodeReader; /** * Build a frame window to run all the GDSC SMLM ImageJ plugins defined in gdsc/smlm/plugins.config. Also add these * commands to the plugins menu. */ public class SMLMTools extends PlugInFrame implements ActionListener { private static final long serialVersionUID = -5457127382849923056L; private static final String TITLE = "GDSC SMLM ImageJ Plugins"; private static final String OPT_LOCATION = "SMLM_Plugins.location"; private static PlugInFrame instance; private HashMap<String, String[]> plugins = new HashMap<String, String[]>(); private boolean addSpacer = false; /** * Constructor. * <p> * Create a frame showing all the available plugins within the user [ImageJ]/plugins/smlm.config file or the default * gdsc/smlm/plugins.config file. */ public SMLMTools() { super(TITLE); // Only allow one instance to run if (isFrameVisible()) { if (!(instance.getTitle().equals(getTitle()))) { closeFrame(); } else { instance.toFront(); return; } } if (!createFrame()) return; instance = this; WindowManager.addWindow(this); pack(); Point loc = Prefs.getLocation(OPT_LOCATION); if (loc != null) setLocation(loc); else { GUI.center(this); } if (IJ.isMacOSX()) setResizable(false); setVisible(true); } /* * (non-Javadoc) * * @see ij.plugin.frame.PlugInFrame#windowClosing(java.awt.event.WindowEvent) */ public void windowClosing(WindowEvent e) { Prefs.saveLocation(OPT_LOCATION, getLocation()); instance = null; close(); } /** * @return True if the instance of the SMLM Tools Frame is visible */ public static boolean isFrameVisible() { return (instance != null && instance.isVisible()); } /** * Close the instance of the SMLM Tools Frame */ public static void closeFrame() { if (instance != null) { Prefs.saveLocation(OPT_LOCATION, instance.getLocation()); instance.close(); instance = null; } } /* * (non-Javadoc) * * @see ij.plugin.frame.PlugInFrame#run(java.lang.String) */ public void run(String arg) { SMLMUsageTracker.recordPlugin(this.getClass(), arg); // Do nothing. The frame has been created and the buttons run the plugins. } private boolean createFrame() { // Locate all the GDSC SMLM plugins using the plugins.config: InputStream readmeStream = getToolsPluginsConfig(); ij.Menus.installPlugin("", ij.Menus.PLUGINS_MENU, "-", "", IJ.getInstance()); // Read into memory ArrayList<String[]> plugins = new ArrayList<String[]>(); int gaps = 0; BufferedReader input = null; try { input = new BufferedReader(new UnicodeReader(readmeStream, null)); String line; while ((line = input.readLine()) != null) { if (line.startsWith("#")) continue; String[] tokens = line.split(","); if (tokens.length == 3) { // Only copy the entries from the Plugins menu if (!ignore(tokens)) { if (!plugins.isEmpty()) { // Multiple gaps indicates a new column if (gaps > 1) { plugins.add(new String[] { "next", "" }); } } gaps = 0; plugins.add(new String[] { tokens[1].trim(), tokens[2].trim() }); } } else gaps++; // Put a spacer between plugins if specified if ((tokens.length == 2 && tokens[0].startsWith("Plugins") && tokens[1].trim().equals("\"-\"")) || line.length() == 0) { plugins.add(new String[] { "spacer", "" }); } } } catch (IOException e) { // Ignore } finally { if (input != null) { try { input.close(); } catch (IOException e) { // Ignore } } } if (plugins.isEmpty()) return false; // Arrange on a grid Panel mainPanel = new Panel(); GridBagLayout grid = new GridBagLayout(); mainPanel.setLayout(grid); add(mainPanel); addSpacer = false; int col = 0, row = 0; for (String[] plugin : plugins) { if (plugin[0].equals("next")) { col++; row = 0; } else if (plugin[0].equals("spacer")) addSpacer = true; else row = addPlugin(mainPanel, grid, plugin[0], plugin[1], col, row); } return true; } /** * Selectively ignore certain plugins * * @param tokens * The tokens from the plugins.config file * @return true if the plugin should be ignored */ private boolean ignore(String[] tokens) { // Only copy the entries from the Plugins menu if (!tokens[0].startsWith("Plugins")) return true; // This plugin cannot be run unless in a macro if (tokens[1].contains("SMLM Macro Extensions")) return true; return false; } private static InputStream getToolsPluginsConfig() { // Look for smlm.config in the plugin directory String pluginsDir = IJ.getDirectory("plugins"); String filename = pluginsDir + File.separator + "smlm.config"; if (new File(filename).exists()) { try { return new FileInputStream(filename); } catch (FileNotFoundException e) { // Ignore and resort to default } } // Fall back to the embedded config in the jar file return getPluginsConfig(); } public static InputStream getPluginsConfig() { // Get the embedded config in the jar file Class<SMLMTools> resourceClass = SMLMTools.class; InputStream readmeStream = resourceClass.getResourceAsStream("/gdsc/smlm/plugins.config"); return readmeStream; } private int addPlugin(Panel mainPanel, GridBagLayout grid, String commandName, final String command, int col, int row) { // Disect the ImageJ plugins.config string, e.g.: // Plugins>GDSC SMLM, "Peak Fit", gdsc.smlm.ij.plugins.PeakFit commandName = commandName.replaceAll("\"", ""); Button button = new Button(commandName); String className = command; String arg = ""; int index = command.indexOf('('); if (index > 0) { className = command.substring(0, index); int argStart = command.indexOf('"'); if (argStart > 0) { int argEnd = command.lastIndexOf('"'); arg = command.substring(argStart + 1, argEnd); } } // Add to Plugins menu so that the macros/toolset will work if (!ij.Menus.commandInUse(commandName)) { if (addSpacer) { try { ij.Menus.getImageJMenu("Plugins").addSeparator(); } catch (NoSuchMethodError e) { // Ignore. This ImageJ method is from IJ 1.48+ } } ij.Menus.installPlugin(command, ij.Menus.PLUGINS_MENU, commandName, "", IJ.getInstance()); } // Store the command to be invoked when the button is clicked plugins.put(commandName, new String[] { className, arg }); button.addActionListener(this); if (addSpacer) { addSpacer = false; if (row != 0) row = add(mainPanel, grid, new Panel(), col, row); } row = add(mainPanel, grid, button, col, row); return row; } private int add(Panel mainPanel, GridBagLayout grid, Component comp, int col, int row) { GridBagConstraints c = new GridBagConstraints(); c.gridx = col; c.gridy = row++; c.fill = GridBagConstraints.BOTH; if (col > 0) c.insets.left = 10; grid.setConstraints(comp, c); mainPanel.add(comp); return row; } public void actionPerformed(ActionEvent e) { // Get the plugin from the button label and run it Button button = (Button) e.getSource(); String commandName = button.getLabel(); //String[] args = plugins.get(commandName); //IJ.runPlugIn(commandName, args[0], args[1]); // Only in IJ 1.47+ //IJ.runPlugIn(args[0], args[1]); // Use the IJ executer to run in a background thread new Executer(commandName, null); } }