| Executer |

    package ij;
    import ij.util.Tools;
    import ij.text.TextWindow;
    import ij.plugin.MacroInstaller;
    import ij.plugin.frame.Recorder;
    import java.io.*;
    import java.util.*;
    import java.awt.event.KeyEvent;

    /** Runs ImageJ menu commands in a separate thread.*/
    public class Executer implements Runnable {

        private static String previousCommand;

        private String command;
        private Thread thread;

        /** Create an Executer to run the specified menu command
            in this thread using the active image. */
        public Executer(String cmd) {
            command = cmd;
        }

        /** Create an Executer that runs the specified menu command
            in a separate thread using the active image image. */
        public Executer(String cmd, ImagePlus ignored) {
            if (cmd.startsWith("Repeat")) {
                command = previousCommand;
                IJ.setKeyUp(KeyEvent.VK_SHIFT);
            } else {
                command = cmd;
                if (!(cmd.equals("Undo")||cmd.equals("Close")))
                    previousCommand = cmd;
            }
            IJ.resetEscape();
            thread = new Thread(this, cmd);
            thread.setPriority(Math.max(thread.getPriority()-2, Thread.MIN_PRIORITY));
            thread.start();
        }

        public void run() {
            if (command==null) return;
            try {
                if (Recorder.record) {
                    Recorder.setCommand(command);
                    runCommand(command);
                    Recorder.saveCommand();
                } else
                    runCommand(command);
            } catch(Throwable e) {
                IJ.showStatus("");
                IJ.showProgress(1.0);
                ImagePlus imp = WindowManager.getCurrentImage();
                if (imp!=null) imp.unlock();
                String msg = e.getMessage();
                if (e instanceof OutOfMemoryError)
                    IJ.outOfMemory(command);
                else if (e instanceof RuntimeException && msg!=null && msg.equals(Macro.MACRO_CANCELED))
                    ; //do nothing
                else {
                    CharArrayWriter caw = new CharArrayWriter();
                    PrintWriter pw = new PrintWriter(caw);
                    e.printStackTrace(pw);
                    String s = caw.toString();
                    if (IJ.isMacintosh()) {
                        if (s.indexOf("ThreadDeath")>0)
                            return;
                        s = Tools.fixNewLines(s);
                    }
                    if (IJ.getInstance()!=null)
                        new TextWindow("Exception", s, 350, 250);
                    else
                        IJ.log(s);
                }
            }
        }

        void runCommand(String cmd) {
            Hashtable table = Menus.getCommands();
            String className = (String)table.get(cmd);
            if (className!=null) {
                String arg = "";
                if (className.endsWith("\")")) {
                    // extract string argument (e.g. className("arg"))
                    int argStart = className.lastIndexOf("(\"");
                    if (argStart>0) {
                        arg = className.substring(argStart+2, className.length()-2);
                        className = className.substring(0, argStart);
                    }
                }
                if (IJ.shiftKeyDown() && className.startsWith("ij.plugin.Macro_Runner")) {
                    IJ.open(IJ.getDirectory("plugins")+arg);
                    IJ.setKeyUp(KeyEvent.VK_SHIFT);
                } else
                    IJ.runPlugIn(cmd, className, arg);
            } else {
                // Is this command in Plugins>Macros?
                if (MacroInstaller.runMacroCommand(cmd))
                    return;
                // Is this command a LUT name?
                String path = Prefs.getHomeDir()+File.separator+"luts"+File.separator+cmd+".lut";
                File f = new File(path);
                if (f.exists())
                    IJ.open(path);
                else
                    IJ.error("Unrecognized command: " + cmd);
            }
        }

        /** Returns the last command executed. Returns null
            if no command has been executed. */
        public static String getCommand() {
            return previousCommand;
        }

    }

| Executer |