package ij; import ij.process.*; import ij.util.*; import ij.gui.ImageWindow; import ij.plugin.MacroInstaller; import java.awt.*; import java.awt.image.*; import java.awt.event.*; import java.util.*; import java.io.*; import java.applet.Applet; import java.awt.event.*; import java.util.zip.*; /** This class installs and updates ImageJ's menus. Note that menu labels, even in submenus, must be unique. This is because ImageJ uses a single hash table for all menu labels. If you look closely, you will see that File->Import->Text Image... and File->Save As->Text Image... do not use the same label. One of the labels has an extra space. @see ImageJ */ public class Menus { public static final char PLUGINS_MENU = 'p'; public static final char IMPORT_MENU = 'i'; public static final char SAVE_AS_MENU = 's'; public static final char SHORTCUTS_MENU = 'h'; // 'h'=hotkey public static final char ABOUT_MENU = 'a'; public static final char FILTERS_MENU = 'f'; public static final char TOOLS_MENU = 't'; public static final char UTILITIES_MENU = 'u'; public static final int WINDOW_MENU_ITEMS = 5; // fixed items at top of Window menu public static final int NORMAL_RETURN = 0; public static final int COMMAND_IN_USE = -1; public static final int INVALID_SHORTCUT = -2; public static final int SHORTCUT_IN_USE = -3; public static final int NOT_INSTALLED = -4; public static final int COMMAND_NOT_FOUND = -5; public static final int MAX_OPEN_RECENT_ITEMS = 15; private static MenuBar mbar; private static CheckboxMenuItem gray8Item,gray16Item,gray32Item, color256Item,colorRGBItem,RGBStackItem,HSBStackItem; private static PopupMenu popup; private static ImageJ ij; private static Applet applet; private Hashtable demoImagesTable = new Hashtable(); private static String pluginsPath, macrosPath; private static Properties menus; private static Properties menuSeparators; private static Menu pluginsMenu, saveAsMenu, shortcutsMenu, utilitiesMenu, macrosMenu; static Menu window, openRecentMenu; private static Hashtable pluginsTable; private static int nPlugins, nMacros; private static Hashtable shortcuts; private static Hashtable macroShortcuts; private static Vector pluginsPrefs; // commands saved in IJ_Prefs static int windowMenuItems2; // non-image windows listed in Window menu + separator private String error; private String jarError; private String pluginError; private boolean isJarErrorHeading; private static boolean installingJars, duplicateCommand; private static Vector jarFiles; // JAR files in plugins folder with "_" in their name private static Vector macroFiles; // Macro files in plugins folder with "_" in their name private static int userPluginsIndex; // First user plugin or submenu in Plugins menu private static boolean addSorted; private static int defaultFontSize = IJ.isWindows()?14:0; private static int fontSize = Prefs.getInt(Prefs.MENU_SIZE, defaultFontSize); private static Font menuFont; static boolean jnlp; // true when using Java WebStart Menus(ImageJ ijInstance, Applet appletInstance) { ij = ijInstance; applet = appletInstance; } String addMenuBar() { nPlugins = nMacros = userPluginsIndex = 0; addSorted = installingJars = duplicateCommand = false; error = null; mbar = null; menus = new Properties(); pluginsTable = new Hashtable(); shortcuts = new Hashtable(); pluginsPrefs = new Vector(); macroShortcuts = null; Menu file = getMenu("File"); Menu newMenu = getMenu("File>New", true); addPlugInItem(file, "Open...", "ij.plugin.Commands(\"open\")", KeyEvent.VK_O, false); addPlugInItem(file, "Open Next", "ij.plugin.NextImageOpener", KeyEvent.VK_O, true); getMenu("File>Open Samples", true); addOpenRecentSubMenu(file); Menu importMenu = getMenu("File>Import", true); file.addSeparator(); addPlugInItem(file, "Close", "ij.plugin.Commands(\"close\")", KeyEvent.VK_W, false); addPlugInItem(file, "Save", "ij.plugin.Commands(\"save\")", KeyEvent.VK_S, false); saveAsMenu = getMenu("File>Save As", true); addPlugInItem(file, "Revert", "ij.plugin.Commands(\"revert\")", KeyEvent.VK_R, false); file.addSeparator(); addPlugInItem(file, "Page Setup...", "ij.plugin.filter.Printer(\"setup\")", 0, false); addPlugInItem(file, "Print...", "ij.plugin.filter.Printer(\"print\")", KeyEvent.VK_P, false); Menu edit = getMenu("Edit"); addPlugInItem(edit, "Undo", "ij.plugin.Commands(\"undo\")", KeyEvent.VK_Z, false); edit.addSeparator(); addPlugInItem(edit, "Cut", "ij.plugin.Clipboard(\"cut\")", KeyEvent.VK_X, false); addPlugInItem(edit, "Copy", "ij.plugin.Clipboard(\"copy\")", KeyEvent.VK_C, false); addPlugInItem(edit, "Copy to System", "ij.plugin.Clipboard(\"scopy\")", 0, false); addPlugInItem(edit, "Paste", "ij.plugin.Clipboard(\"paste\")", KeyEvent.VK_V, false); addPlugInItem(edit, "Paste Control...", "ij.plugin.frame.PasteController", 0, false); edit.addSeparator(); addPlugInItem(edit, "Clear", "ij.plugin.filter.Filler(\"clear\")", 0, false); addPlugInItem(edit, "Clear Outside", "ij.plugin.filter.Filler(\"outside\")", 0, false); addPlugInItem(edit, "Fill", "ij.plugin.filter.Filler(\"fill\")", KeyEvent.VK_F, false); addPlugInItem(edit, "Draw", "ij.plugin.filter.Filler(\"draw\")", KeyEvent.VK_D, false); addPlugInItem(edit, "Invert", "ij.plugin.filter.Filters(\"invert\")", KeyEvent.VK_I, true); edit.addSeparator(); getMenu("Edit>Selection", true); Menu optionsMenu = getMenu("Edit>Options", true); Menu image = getMenu("Image"); Menu imageType = getMenu("Image>Type"); gray8Item = addCheckboxItem(imageType, "8-bit", "ij.plugin.Converter(\"8-bit\")"); gray16Item = addCheckboxItem(imageType, "16-bit", "ij.plugin.Converter(\"16-bit\")"); gray32Item = addCheckboxItem(imageType, "32-bit", "ij.plugin.Converter(\"32-bit\")"); color256Item = addCheckboxItem(imageType, "8-bit Color", "ij.plugin.Converter(\"8-bit Color\")"); colorRGBItem = addCheckboxItem(imageType, "RGB Color", "ij.plugin.Converter(\"RGB Color\")"); imageType.add(new MenuItem("-")); RGBStackItem = addCheckboxItem(imageType, "RGB Stack", "ij.plugin.Converter(\"RGB Stack\")"); HSBStackItem = addCheckboxItem(imageType, "HSB Stack", "ij.plugin.Converter(\"HSB Stack\")"); image.add(imageType); image.addSeparator(); getMenu("Image>Adjust", true); addPlugInItem(image, "Show Info...", "ij.plugin.filter.Info", KeyEvent.VK_I, false); addPlugInItem(image, "Properties...", "ij.plugin.filter.ImageProperties", KeyEvent.VK_P, true); getMenu("Image>Color", true); getMenu("Image>Stacks", true); Menu hyperstacksMenu = getMenu("Image>Hyperstacks", true); image.addSeparator(); addPlugInItem(image, "Crop", "ij.plugin.filter.Resizer(\"crop\")", KeyEvent.VK_X, true); addPlugInItem(image, "Duplicate...", "ij.plugin.filter.Duplicater", KeyEvent.VK_D, true); addPlugInItem(image, "Rename...", "ij.plugin.SimpleCommands(\"rename\")", 0, false); addPlugInItem(image, "Scale...", "ij.plugin.Scaler", KeyEvent.VK_E, false); addPlugInItem(image, "Translate...", "ij.plugin.filter.Translator", 0, false); getMenu("Image>Rotate", true); getMenu("Image>Zoom", true); image.addSeparator(); getMenu("Image>Lookup Tables", true); Menu process = getMenu("Process"); addPlugInItem(process, "Smooth", "ij.plugin.filter.Filters(\"smooth\")", KeyEvent.VK_S, true); addPlugInItem(process, "Sharpen", "ij.plugin.filter.Filters(\"sharpen\")", 0, false); addPlugInItem(process, "Find Edges", "ij.plugin.filter.Filters(\"edge\")", 0, false); addPlugInItem(process, "Enhance Contrast", "ij.plugin.ContrastEnhancer", 0, false); getMenu("Process>Noise", true); getMenu("Process>Shadows", true); getMenu("Process>Binary", true); getMenu("Process>Math", true); getMenu("Process>FFT", true); Menu filtersMenu = getMenu("Process>Filters", true); process.addSeparator(); addPlugInItem(process, "Image Calculator...", "ij.plugin.ImageCalculator", 0, false); addPlugInItem(process, "Subtract Background...", "ij.plugin.filter.BackgroundSubtracter", 0, false); addItem(process, "Repeat Command", KeyEvent.VK_R, true); Menu analyzeMenu = getMenu("Analyze"); addPlugInItem(analyzeMenu, "Measure", "ij.plugin.filter.Analyzer", KeyEvent.VK_M, false); addPlugInItem(analyzeMenu, "Analyze Particles...", "ij.plugin.filter.ParticleAnalyzer", 0, false); addPlugInItem(analyzeMenu, "Summarize", "ij.plugin.filter.Analyzer(\"sum\")", 0, false); addPlugInItem(analyzeMenu, "Distribution...", "ij.plugin.Distribution", 0, false); addPlugInItem(analyzeMenu, "Label", "ij.plugin.filter.Filler(\"label\")", 0, false); addPlugInItem(analyzeMenu, "Clear Results", "ij.plugin.filter.Analyzer(\"clear\")", 0, false); addPlugInItem(analyzeMenu, "Set Measurements...", "ij.plugin.filter.Analyzer(\"set\")", 0, false); analyzeMenu.addSeparator(); addPlugInItem(analyzeMenu, "Set Scale...", "ij.plugin.filter.ScaleDialog", 0, false); addPlugInItem(analyzeMenu, "Calibrate...", "ij.plugin.filter.Calibrator", 0, false); addPlugInItem(analyzeMenu, "Histogram", "ij.plugin.Histogram", KeyEvent.VK_H, false); addPlugInItem(analyzeMenu, "Plot Profile", "ij.plugin.filter.Profiler(\"plot\")", KeyEvent.VK_K, false); addPlugInItem(analyzeMenu, "Surface Plot...", "ij.plugin.SurfacePlotter", 0, false); getMenu("Analyze>Gels", true); Menu toolsMenu = getMenu("Analyze>Tools", true); // the plugins will be added later, with a separator addPluginsMenu(); Menu window = getMenu("Window"); addPlugInItem(window, "Show All", "ij.plugin.WindowOrganizer(\"show\")", KeyEvent.VK_F, true); addPlugInItem(window, "Put Behind [tab]", "ij.plugin.Commands(\"tab\")", 0, false); addPlugInItem(window, "Cascade", "ij.plugin.WindowOrganizer(\"cascade\")", 0, false); addPlugInItem(window, "Tile", "ij.plugin.WindowOrganizer(\"tile\")", 0, false); window.addSeparator(); Menu help = getMenu("Help"); addPlugInItem(help, "ImageJ Website...", "ij.plugin.BrowserLauncher", 0, false); addPlugInItem(help, "ImageJ News...", "ij.plugin.BrowserLauncher(\""+IJ.URL+"/notes.html\")", 0, false); addPlugInItem(help, "Documentation...", "ij.plugin.BrowserLauncher(\""+IJ.URL+"/docs\")", 0, false); addPlugInItem(help, "Installation...", "ij.plugin.SimpleCommands(\"install\")", 0, false); addPlugInItem(help, "Search Website...", "ij.plugin.BrowserLauncher(\""+IJ.URL+"/search.html\")", 0, false); addPlugInItem(help, "List Archives...", "ij.plugin.BrowserLauncher(\"https://list.nih.gov/archives/imagej.html\")", 0, false); help.addSeparator(); addPlugInItem(help, "Dev. Resources...", "ij.plugin.BrowserLauncher(\""+IJ.URL+"/developer/index.html\")", 0, false); addPlugInItem(help, "Plugins...", "ij.plugin.BrowserLauncher(\""+IJ.URL+"/plugins\")", 0, false); addPlugInItem(help, "Macros...", "ij.plugin.BrowserLauncher(\""+IJ.URL+"/macros/\")", 0, false); addPlugInItem(help, "Macro Functions...", "ij.plugin.BrowserLauncher(\""+IJ.URL+"/developer/macro/functions.html\")", 0, false); help.addSeparator(); addPlugInItem(help, "Update ImageJ...", "ij.plugin.ImageJ_Updater", 0, false); addPlugInItem(help, "Update Menus", "ij.plugin.ImageJ_Updater(\"menus\")", 0, false); help.addSeparator(); Menu aboutMenu = getMenu("Help>About Plugins", true); addPlugInItem(help, "About ImageJ...", "ij.plugin.AboutBox", 0, false); if (applet==null) { menuSeparators = new Properties(); installPlugins(); } // make sure "Quit" is the last item in the File menu file.addSeparator(); addPlugInItem(file, "Quit", "ij.plugin.Commands(\"quit\")", 0, false); if (fontSize!=0) mbar.setFont(getFont()); if (ij!=null) ij.setMenuBar(mbar); if (pluginError!=null) error = error!=null?error+="\n"+pluginError:pluginError; if (jarError!=null) error = error!=null?error+="\n"+jarError:jarError; return error; } void addOpenRecentSubMenu(Menu menu) { openRecentMenu = getMenu("File>Open Recent"); for (int i=0; i0) key = key.substring(0, index); for (int count=1; count<100; count++) { value = Prefs.getString(key + (count/10)%10 + count%10); if (value==null) break; if (count==1) menu.add(submenu); if (value.equals("-")) submenu.addSeparator(); else addPluginItem(submenu, value); } if (name.equals("Lookup Tables") && applet==null) addLuts(submenu); return submenu; } static void addLuts(Menu submenu) { String path = Prefs.getHomeDir()+File.separator; File f = new File(path+"luts"); String[] list = null; if (applet==null && f.exists() && f.isDirectory()) list = f.list(); if (list==null) return; if (IJ.isLinux()) StringSorter.sort(list); submenu.addSeparator(); for (int i=0; i0) { String shortcut = command.substring(openBracket+1,command.length()-1); keyCode = convertShortcutToCode(shortcut); boolean functionKey = keyCode>=KeyEvent.VK_F1 && keyCode<=KeyEvent.VK_F12; if (keyCode>0 && !functionKey) command = command.substring(0,openBracket); //IJ.write(command+": "+shortcut); } } if (keyCode>=KeyEvent.VK_F1 && keyCode<=KeyEvent.VK_F12) { shortcuts.put(new Integer(keyCode),command); keyCode = 0; } else if (keyCode>=265 && keyCode<=290) { keyCode -= 200; shift = true; } addItem(submenu,command,keyCode,shift); while(s.charAt(lastComma+1)==' ' && lastComma+2') { String submenu = value.substring(2,value.length()-1); //Menu menu = getMenu("Plugins>" + submenu, true); Menu menu = addSubMenu(pluginsMenu, submenu); if (submenu.equals("Shortcuts")) shortcutsMenu = menu; else if (submenu.equals("Utilities")) utilitiesMenu = menu; else if (submenu.equals("Macros")) macrosMenu = menu; } else addPluginItem(pluginsMenu, value); } userPluginsIndex = pluginsMenu.getItemCount(); if (userPluginsIndex<0) userPluginsIndex = 0; } /** Install plugins using "pluginxx=" keys in IJ_Prefs.txt. Plugins not listed in IJ_Prefs are added to the end of the Plugins menu. */ void installPlugins() { String value, className; char menuCode; Menu menu; String[] plugins = getPlugins(); String[] plugins2 = null; Hashtable skipList = new Hashtable(); for (int index=0; index<100; index++) { value = Prefs.getString("plugin" + (index/10)%10 + index%10); if (value==null) break; menuCode = value.charAt(0); switch (menuCode) { case PLUGINS_MENU: default: menu = pluginsMenu; break; case IMPORT_MENU: menu = getMenu("File>Import"); break; case SAVE_AS_MENU: menu = getMenu("File>Save As"); break; case SHORTCUTS_MENU: menu = shortcutsMenu; break; case ABOUT_MENU: menu = getMenu("Help>About Plugins"); break; case FILTERS_MENU: menu = getMenu("Process>Filters"); break; case TOOLS_MENU: menu = getMenu("Analyze>Tools"); break; case UTILITIES_MENU: menu = utilitiesMenu; break; } String prefsValue = value; value = value.substring(2,value.length()); //remove menu code and coma className = value.substring(value.lastIndexOf(',')+1,value.length()); boolean found = className.startsWith("ij."); if (!found && plugins!=null) { // does this plugin exist? if (plugins2==null) plugins2 = getStrippedPlugins(plugins); for (int i=0; i0) className = className.substring(0, argStart); } skipList.put(className, ""); } } if (plugins!=null) { for (int i=0; i0) { dir = name.substring(0, slashIndex); name = name.substring(slashIndex+1, name.length()); menu = getPluginsSubmenu(dir); } String command = name.replace('_',' '); if (command.endsWith(".js")) command = command.substring(0, command.length()-3); //remove ".js" else command = command.substring(0, command.length()-4); //remove ".txt" or ".ijm" command.trim(); if (pluginsTable.get(command)!=null) // duplicate command? command = command + " Macro"; MenuItem item = new MenuItem(command); addOrdered(menu, item); item.addActionListener(ij); String path = (dir!=null?dir+File.separator:"") + name; pluginsTable.put(command, "ij.plugin.Macro_Runner(\""+path+"\")"); nMacros++; } static int addPluginSeparatorIfNeeded(Menu menu) { if (menuSeparators == null) return 0; Integer i = (Integer)menuSeparators.get(menu); if (i == null) { if (menu.getItemCount() > 0) addSeparator(menu); i = new Integer(menu.getItemCount()); menuSeparators.put(menu, i); } return i.intValue(); } /** Inserts 'item' into 'menu' in alphanumeric order. */ static void addOrdered(Menu menu, MenuItem item) { String label = item.getLabel(); int start = addPluginSeparatorIfNeeded(menu); for (int i=start; i=3 && !s.startsWith("#")) { entries[nEntries++] = s; if (s.startsWith("Plugins>")) nEntries2++; } } } catch (IOException e) {} finally { try {if (lnr!=null) lnr.close();} catch (IOException e) {} } for (int j=0; j")) { int firstComma = s.indexOf(','); int firstQuote = s.indexOf('"'); boolean pluginsDir = (new File(jar)).getParent().endsWith("plugins"); if (firstComma>8 && firstQuote>firstComma && !pluginsDir) { String submenuName = s.substring(8, firstComma); String prefix = ""; // "Extended Depth of Field" and "Particle Detector & Tracker" plugins if (submenuName.startsWith("Extend")||submenuName.startsWith("Particle D")) prefix = submenuName+": "; //IJ.log(nEntries+" "+nEntries2+" "+jar+" "+s+" "+submenuName); s = "Plugins, \""+prefix+s.substring(firstQuote+1, s.length()); } } } installJarPlugin(jar, s); } } } /** Install a plugin located in a JAR file. */ void installJarPlugin(String jar, String s) { addSorted = false; Menu menu; if (s.startsWith("Plugins>")) { int firstComma = s.indexOf(','); if (firstComma==-1 || firstComma<=8) menu = null; else { String name = s.substring(8, firstComma); menu = getPluginsSubmenu(name); } } else if (s.startsWith("\"") || s.startsWith("Plugins")) { String name = getSubmenuName(jar); if (name!=null) menu = getPluginsSubmenu(name); else menu = pluginsMenu; addSorted = true; } else { int firstQuote = s.indexOf('"'); String name = firstQuote < 0 ? s : s.substring(0, firstQuote).trim(); int comma = name.indexOf(','); if (comma >= 0) name = name.substring(0, comma); if (name.startsWith("Help>About")) // for backward compatibility name = "Help>About Plugins"; menu = getMenu(name); } int firstQuote = s.indexOf('"'); if (firstQuote==-1) return; s = s.substring(firstQuote, s.length()); // remove menu if (menu!=null) { addPluginSeparatorIfNeeded(menu); addPluginItem(menu, s); addSorted = false; } if (duplicateCommand) { if (jarError==null) jarError = ""; addJarErrorHeading(jar); jarError += " Duplicate command: " + s + "\n"; } duplicateCommand = false; } void addJarErrorHeading(String jar) { if (!isJarErrorHeading) { if (!jarError.equals("")) jarError += " \n"; jarError += "Plugin configuration error: " + jar + "\n"; isJarErrorHeading = true; } } private static Menu getMenu(String menuName) { return getMenu(menuName, false); } private static Menu getMenu(String menuName, boolean readFromProps) { if (menuName.endsWith(">")) menuName = menuName.substring(0, menuName.length() - 1); Menu result = (Menu)menus.get(menuName); if (result == null) { int offset = menuName.lastIndexOf('>'); if (offset < 0) { result = new Menu(menuName); if (mbar == null) mbar = new MenuBar(); if (menuName.equals("Help")) mbar.setHelpMenu(result); else mbar.add(result); if (menuName.equals("Window")) window = result; else if (menuName.equals("Plugins")) pluginsMenu = result; } else { String parentName = menuName.substring(0, offset); String menuItemName = menuName.substring(offset + 1); Menu parentMenu = getMenu(parentName); result = new Menu(menuItemName); addPluginSeparatorIfNeeded(parentMenu); if (readFromProps) result = addSubMenu(parentMenu, menuItemName); else if (parentName.startsWith("Plugins") && menuSeparators != null) addItemSorted(parentMenu, result, parentName.equals("Plugins") ? userPluginsIndex : 0); else parentMenu.add(result); if (menuName.equals("File>Open Recent")) openRecentMenu = result; } menus.put(menuName, result); } return result; } Menu getPluginsSubmenu(String submenuName) { return getMenu("Plugins>" + submenuName); } String getSubmenuName(String jarPath) { //IJ.log("getSubmenuName: \n"+jarPath+"\n"+pluginsPath); if(pluginsPath == null) return null; if (jarPath.startsWith(pluginsPath)) jarPath = jarPath.substring(pluginsPath.length() - 1); int index = jarPath.lastIndexOf(File.separatorChar); if (index<0) return null; String name = jarPath.substring(0, index); index = name.lastIndexOf(File.separatorChar); if (index<0) return null; name = name.substring(index+1); if (name.equals("plugins")) return null; return name; } static void addItemSorted(Menu menu, MenuItem item, int startingIndex) { String itemLabel = item.getLabel(); int count = menu.getItemCount(); boolean inserted = false; for (int i=startingIndex; i0 && name.indexOf("$")==-1 && name.indexOf("/_")==-1 && !name.startsWith("_")) { if (sb==null) sb = new StringBuffer(); String className = name.substring(0, name.length()-6); int slashIndex = className.lastIndexOf('/'); String plugins = "Plugins"; if (slashIndex >= 0) { plugins += ">" + className.substring(0, slashIndex).replace('/', '>').replace('_', ' '); name = className.substring(slashIndex + 1); } else name = className; name = name.replace('_', ' '); className = className.replace('/', '.'); sb.append(plugins + ", \""+name+"\", "+className+"\n"); } } } catch (Exception e) {} //IJ.log(""+(sb!=null?sb.toString():"null")); if (sb==null) return null; else return new ByteArrayInputStream(sb.toString().getBytes()); } /** Returns a list of the plugins with directory names removed. */ String[] getStrippedPlugins(String[] plugins) { String[] plugins2 = new String[plugins.length]; int slashPos; for (int i=0; i=0) plugins2[i] = plugins[i].substring(slashPos+1,plugins2[i].length()); } return plugins2; } /** Returns a list of the plugins in the plugins menu. */ public static synchronized String[] getPlugins() { String homeDir = Prefs.getHomeDir(); if (homeDir==null) return null; if (homeDir.endsWith("plugins")) pluginsPath = homeDir+Prefs.separator; else { String property = System.getProperty("plugins.dir"); if (property!=null && (property.endsWith("/")||property.endsWith("\\"))) property = property.substring(0, property.length()-1); String pluginsDir = property; if (pluginsDir==null) pluginsDir = homeDir; else if (pluginsDir.equals("user.home")) { pluginsDir = System.getProperty("user.home"); if (!(new File(pluginsDir+Prefs.separator+"plugins")).isDirectory()) pluginsDir = pluginsDir + Prefs.separator + "ImageJ"; property = null; // needed to run plugins when ImageJ launched using Java WebStart if (applet==null) System.setSecurityManager(null); jnlp = true; } pluginsPath = pluginsDir+Prefs.separator+"plugins"+Prefs.separator; if (property!=null&&!(new File(pluginsPath)).isDirectory()) pluginsPath = pluginsDir + Prefs.separator; macrosPath = pluginsDir+Prefs.separator+"macros"+Prefs.separator; } File f = macrosPath!=null?new File(macrosPath):null; if (f!=null && !f.isDirectory()) macrosPath = null; f = pluginsPath!=null?new File(pluginsPath):null; if (f==null || (f!=null && !f.isDirectory())) { //error = "Plugins folder not found at "+pluginsPath; pluginsPath = null; return null; } String[] list = f.list(); if (list==null) return null; Vector v = new Vector(); jarFiles = null; macroFiles = null; for (int i=0; i=0; if (hasUnderscore && isClassFile && name.indexOf('$')<0 ) { name = name.substring(0, name.length()-6); // remove ".class" v.addElement(name); } else if (hasUnderscore && (name.endsWith(".jar") || name.endsWith(".zip"))) { if (jarFiles==null) jarFiles = new Vector(); jarFiles.addElement(pluginsPath + name); } else if ((hasUnderscore&&name.endsWith(".txt")) || name.endsWith(".ijm") || name.endsWith(".js")) { if (macroFiles==null) macroFiles = new Vector(); macroFiles.addElement(name); } else { if (!isClassFile) checkSubdirectory(pluginsPath, name, v); } } list = new String[v.size()]; v.copyInto((String[])list); StringSorter.sort(list); return list; } /** Looks for plugins and jar files in a subdirectory of the plugins directory. */ private static void checkSubdirectory(String path, String dir, Vector v) { if (dir.endsWith(".java")) return; File f = new File(path, dir); if (!f.isDirectory()) return; String[] list = f.list(); if (list==null) return; dir += "/"; int classCount=0, otherCount=0; String className = null; for (int i=0; i=0; if (hasUnderscore && name.endsWith(".class") && name.indexOf('$')<0) { name = name.substring(0, name.length()-6); // remove ".class" v.addElement(dir+name); classCount++; className = name; //IJ.write("File: "+f+"/"+name); } else if (hasUnderscore && (name.endsWith(".jar") || name.endsWith(".zip"))) { if (jarFiles==null) jarFiles = new Vector(); jarFiles.addElement(f.getPath() + File.separator + name); otherCount++; } else if ((hasUnderscore&&name.endsWith(".txt")) || name.endsWith(".ijm") || name.endsWith(".js")) { if (macroFiles==null) macroFiles = new Vector(); macroFiles.addElement(dir + name); otherCount++; } } if (Prefs.moveToMisc && classCount==1 && otherCount==0 && dir.indexOf("_")==-1) v.setElementAt("Miscellaneous/" + className, v.size() - 1); } /** Installs a plugin in the Plugins menu using the class name, with underscores replaced by spaces, as the command. */ void installUserPlugin(String className) { installUserPlugin(className, false); } public void installUserPlugin(String className, boolean force) { int slashIndex = className.indexOf('/'); String menuName = slashIndex < 0 ? "Plugins" : "Plugins>" + className.substring(0, slashIndex).replace('/', '>'); Menu menu = getMenu(menuName); String command = className; if (slashIndex>0) { command = className.substring(slashIndex+1); } command = command.replace('_',' '); command.trim(); boolean itemExists = (pluginsTable.get(command)!=null); if(force && itemExists) return; if (!force && itemExists) // duplicate command? command = command + " Plugin"; MenuItem item = new MenuItem(command); if(force) addItemSorted(menu,item,0); else addOrdered(menu, item); item.addActionListener(ij); pluginsTable.put(command, className.replace('/', '.')); nPlugins++; } void installPopupMenu(ImageJ ij) { String s; int count = 0; MenuItem mi; popup = new PopupMenu(""); if (fontSize!=0) popup.setFont(getFont()); while (true) { count++; s = Prefs.getString("popup" + (count/10)%10 + count%10); if (s==null) break; if (s.equals("-")) popup.addSeparator(); else if (!s.equals("")) { mi = new MenuItem(s); mi.addActionListener(ij); popup.add(mi); } } } public static MenuBar getMenuBar() { return mbar; } public static Menu getMacrosMenu() { return macrosMenu; } public int getMacroCount() { return nMacros; } public int getPluginCount() { return nPlugins; } static final int RGB_STACK=10, HSB_STACK=11; /** Updates the Image/Type and Window menus. */ public static void updateMenus() { if (ij==null) return; gray8Item.setState(false); gray16Item.setState(false); gray32Item.setState(false); color256Item.setState(false); colorRGBItem.setState(false); RGBStackItem.setState(false); HSBStackItem.setState(false); ImagePlus imp = WindowManager.getCurrentImage(); if (imp==null) return; int type = imp.getType(); if (imp.getStackSize()>1) { ImageStack stack = imp.getStack(); if (stack.isRGB()) type = RGB_STACK; else if (stack.isHSB()) type = HSB_STACK; } if (type==ImagePlus.GRAY8) { ImageProcessor ip = imp.getProcessor(); if (ip!=null && ip.getMinThreshold()==ImageProcessor.NO_THRESHOLD && ip.isColorLut()) { type = ImagePlus.COLOR_256; if (!ip.isPseudoColorLut()) imp.setType(ImagePlus.COLOR_256); } } switch (type) { case ImagePlus.GRAY8: gray8Item.setState(true); break; case ImagePlus.GRAY16: gray16Item.setState(true); break; case ImagePlus.GRAY32: gray32Item.setState(true); break; case ImagePlus.COLOR_256: color256Item.setState(true); break; case ImagePlus.COLOR_RGB: colorRGBItem.setState(true); break; case RGB_STACK: RGBStackItem.setState(true); break; case HSB_STACK: HSBStackItem.setState(true); break; } //update Window menu int nItems = window.getItemCount(); int start = WINDOW_MENU_ITEMS + windowMenuItems2; int index = start + WindowManager.getCurrentIndex(); try { // workaround for Linux/Java 5.0/bug for (int i=start; i=2) index--; window.insert(item, index); windowMenuItems2++; if (windowMenuItems2==1) { window.insertSeparator(WINDOW_MENU_ITEMS+windowMenuItems2); windowMenuItems2++; } //IJ.write("insertWindowMenuItem: "+windowMenuItems2); } /** Adds one image to the end of the Window menu. */ static synchronized void addWindowMenuItem(ImagePlus imp) { //IJ.log("addWindowMenuItem: "+imp); if (ij==null) return; String name = imp.getTitle(); int size = (imp.getWidth()*imp.getHeight()*imp.getStackSize())/1024; switch (imp.getType()) { case ImagePlus.GRAY32: case ImagePlus.COLOR_RGB: // 32-bit size *=4; break; case ImagePlus.GRAY16: // 16-bit size *= 2; break; default: // 8-bit ; } CheckboxMenuItem item = new CheckboxMenuItem(name + " " + size + "K"); window.add(item); item.addItemListener(ij); } /** Removes the specified item from the Window menu. */ static synchronized void removeWindowMenuItem(int index) { //IJ.log("removeWindowMenuItem: "+index+" "+windowMenuItems2+" "+window.getItemCount()); if (ij==null) return; try { if (index>=0 && index-1) newLabel += label.substring(index, label.length()); } item.setLabel(newLabel); return; } } } catch (NullPointerException e) {} } /** Adds a file path to the beginning of the File/Open Recent submenu. */ public static synchronized void addOpenRecentItem(String path) { if (ij==null) return; int count = openRecentMenu.getItemCount(); for (int i=0; iImport"); break; case SAVE_AS_MENU: menu = getMenu("File>Save As"); break; case SHORTCUTS_MENU: menu = shortcutsMenu; break; case ABOUT_MENU: menu = getMenu("Help>About Plugins"); break; case FILTERS_MENU: menu = getMenu("Process>Filters"); break; case TOOLS_MENU: menu = getMenu("Analyze>Tools"); break; case UTILITIES_MENU: menu = utilitiesMenu; break; default: return 0; } int code = convertShortcutToCode(shortcut); MenuItem item; boolean functionKey = code>=KeyEvent.VK_F1 && code<=KeyEvent.VK_F12; if (code==0) item = new MenuItem(command); else if (functionKey) { command += " [F"+(code-KeyEvent.VK_F1+1)+"]"; shortcuts.put(new Integer(code),command); item = new MenuItem(command); }else { shortcuts.put(new Integer(code),command); int keyCode = code; boolean shift = false; if (keyCode>=265 && keyCode<=290) { keyCode -= 200; shift = true; } item = new MenuItem(command, new MenuShortcut(keyCode, shift)); } menu.add(item); item.addActionListener(ij); pluginsTable.put(command, plugin); shortcut = code>0 && !functionKey?"["+shortcut+"]":""; //IJ.write("installPlugin: "+menuCode+",\""+command+shortcut+"\","+plugin); pluginsPrefs.addElement(menuCode+",\""+command+shortcut+"\","+plugin); return NORMAL_RETURN; } /** Deletes a command installed by installPlugin. */ public static int uninstallPlugin(String command) { boolean found = false; for (Enumeration en=pluginsPrefs.elements(); en.hasMoreElements();) { String cmd = (String)en.nextElement(); if (cmd.indexOf(command)>0) { pluginsPrefs.removeElement((Object)cmd); found = true; break; } } if (found) return NORMAL_RETURN; else return COMMAND_NOT_FOUND; } public static boolean commandInUse(String command) { if (pluginsTable.get(command)!=null) return true; else return false; } public static int convertShortcutToCode(String shortcut) { int code = 0; int len = shortcut.length(); if (len==2 && shortcut.charAt(0)=='F') { code = KeyEvent.VK_F1+(int)shortcut.charAt(1)-49; if (code>=KeyEvent.VK_F1 && code<=KeyEvent.VK_F9) return code; else return 0; } if (len==3 && shortcut.charAt(0)=='F') { code = KeyEvent.VK_F10+(int)shortcut.charAt(2)-48; if (code>=KeyEvent.VK_F10 && code<=KeyEvent.VK_F12) return code; else return 0; } if (len==2 && shortcut.charAt(0)=='N') { // numeric keypad code = KeyEvent.VK_NUMPAD0+(int)shortcut.charAt(1)-48; if (code>=KeyEvent.VK_NUMPAD0 && code<=KeyEvent.VK_NUMPAD9) return code; switch (shortcut.charAt(1)) { case '/': return KeyEvent.VK_DIVIDE; case '*': return KeyEvent.VK_MULTIPLY; case '-': return KeyEvent.VK_SUBTRACT; case '+': return KeyEvent.VK_ADD; case '.': return KeyEvent.VK_DECIMAL; default: return 0; } } if (len!=1) return 0; int c = (int)shortcut.charAt(0); if (c>=65&&c<=90) //A-Z code = KeyEvent.VK_A+c-65 + 200; else if (c>=97&&c<=122) //a-z code = KeyEvent.VK_A+c-97; else if (c>=48&&c<=57) //0-9 code = KeyEvent.VK_0+c-48; else { switch (c) { case 43: code = KeyEvent.VK_PLUS; break; case 45: code = KeyEvent.VK_MINUS; break; //case 92: code = KeyEvent.VK_BACK_SLASH; break; default: return 0; } } return code; } void installStartupMacroSet() { if (applet!=null) { String docBase = ""+applet.getDocumentBase(); if (!docBase.endsWith("/")) { int index = docBase.lastIndexOf("/"); if (index!=-1) docBase = docBase.substring(0, index+1); } IJ.runPlugIn("ij.plugin.URLOpener", docBase+"StartupMacros.txt"); return; } if (macrosPath==null) { (new MacroInstaller()).installFromIJJar("/macros/StartupMacros.txt"); return; } String path = macrosPath + "StartupMacros.txt"; File f = new File(path); if (!f.exists()) { path = macrosPath + "StartupMacros.ijm"; f = new File(path); if (!f.exists()) { (new MacroInstaller()).installFromIJJar("/macros/StartupMacros.txt"); return; } } String libraryPath = macrosPath + "Library.txt"; f = new File(libraryPath); boolean isLibrary = f.exists(); try { MacroInstaller mi = new MacroInstaller(); if (isLibrary) mi.installLibrary(libraryPath); mi.installFile(path); nMacros += mi.getMacroCount(); } catch (Exception e) {} } static boolean validShortcut(String shortcut) { int len = shortcut.length(); if (shortcut.equals("")) return true; else if (len==1) return true; else if (shortcut.startsWith("F") && (len==2 || len==3)) return true; else return false; } public static boolean shortcutInUse(String shortcut) { int code = convertShortcutToCode(shortcut); if (shortcuts.get(new Integer(code))!=null) return true; else return false; } /** Set the size (in points) used for the fonts in ImageJ menus. Set the size to 0 to use the Java default size. */ public static void setFontSize(int size) { if (size<9 && size!=0) size = 9; if (size>24) size = 24; fontSize = size; } /** Returns the size (in points) used for the fonts in ImageJ menus. Returns 0 if the default font size is being used or if this is a Macintosh. */ public static int getFontSize() { return IJ.isMacintosh()?0:fontSize; } public static Font getFont() { if (menuFont==null) menuFont = new Font("SanSerif", Font.PLAIN, fontSize==0?12:fontSize); return menuFont; } /** Called once when ImageJ quits. */ public static void savePreferences(Properties prefs) { int index = 0; for (Enumeration en=pluginsPrefs.elements(); en.hasMoreElements();) { String key = "plugin" + (index/10)%10 + index%10; String value = (String)en.nextElement(); prefs.put(key, value); index++; } int n = openRecentMenu.getItemCount(); for (int i=0; i