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 Menus instance; 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 Map menuEntry2jarFile = new HashMap(); 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; instance = this; } 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; setupPluginsAndMacrosPaths(); 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, "Close All", "ij.plugin.Commands(\"close-all\")", 0, 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); getMenu("Image>Stacks>Tools_", true); Menu hyperstacksMenu = getMenu("Image>Hyperstacks", true); image.addSeparator(); addPlugInItem(image, "Crop", "ij.plugin.Resizer(\"crop\")", KeyEvent.VK_X, true); addPlugInItem(image, "Duplicate...", "ij.plugin.Duplicator", KeyEvent.VK_D, true); addPlugInItem(image, "Rename...", "ij.plugin.SimpleCommands(\"rename\")", 0, false); addPlugInItem(image, "Scale...", "ij.plugin.Scaler", KeyEvent.VK_E, false); getMenu("Image>Transform", true); getMenu("Image>Zoom", true); getMenu("Image>Overlay", 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, "Find Maxima...", "ij.plugin.filter.MaximumFinder", 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(); getMenu("Process>Batch", true); 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_CLOSE_BRACKET, false); 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, "Mailing List...", "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, "Refresh 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; i<MAX_OPEN_RECENT_ITEMS; i++) { String path = Prefs.getString("recent" + (i/10)%10 + i%10); if (path==null) break; MenuItem item = new MenuItem(path); openRecentMenu.add(item); item.addActionListener(ij); } menu.add(openRecentMenu); } static void addItem(Menu menu, String label, int shortcut, boolean shift) { if (menu==null) return; MenuItem item; if (shortcut==0) item = new MenuItem(label); else { if (shift) { item = new MenuItem(label, new MenuShortcut(shortcut, true)); shortcuts.put(new Integer(shortcut+200),label); } else { item = new MenuItem(label, new MenuShortcut(shortcut)); shortcuts.put(new Integer(shortcut),label); } } if (addSorted) { if (menu==pluginsMenu) addItemSorted(menu, item, userPluginsIndex); else addOrdered(menu, item); } else menu.add(item); item.addActionListener(ij); } void addPlugInItem(Menu menu, String label, String className, int shortcut, boolean shift) { pluginsTable.put(label, className); nPlugins++; addItem(menu, label, shortcut, shift); } CheckboxMenuItem addCheckboxItem(Menu menu, String label, String className) { pluginsTable.put(label, className); nPlugins++; CheckboxMenuItem item = new CheckboxMenuItem(label); menu.add(item); item.addItemListener(ij); item.setState(false); return item; } static Menu addSubMenu(Menu menu, String name) { String value; String key = name.toLowerCase(Locale.US); int index; Menu submenu=new Menu(name.replace('_', ' ')); index = key.indexOf(' '); if (index>0) 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 = IJ.getDirectory("luts"); if (path==null) return; File f = new File(path); 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; i<list.length; i++) { String name = list[i]; if (name.endsWith(".lut")) { name = name.substring(0,name.length()-4); MenuItem item = new MenuItem(name); submenu.add(item); item.addActionListener(ij); nPlugins++; } } } static void addPluginItem(Menu submenu, String s) { if (s.startsWith("\"-\"")) { // add menu separator if command="-" addSeparator(submenu); return; } int lastComma = s.lastIndexOf(','); if (lastComma<=0) return; String command = s.substring(1,lastComma-1); int keyCode = 0; boolean shift = false; if (command.endsWith("]")) { int openBracket = command.lastIndexOf('['); if (openBracket>0) { 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<s.length()) lastComma++; // remove leading spaces String className = s.substring(lastComma+1,s.length()); //IJ.log(command+" "+className); if (installingJars) duplicateCommand = pluginsTable.get(command)!=null; pluginsTable.put(command, className); nPlugins++; } void checkForDuplicate(String command) { if (pluginsTable.get(command)!=null) { } } void addPluginsMenu() { String value,label,className; int index; //pluginsMenu = new Menu("Plugins"); pluginsMenu = getMenu("Plugins"); for (int count=1; count<100; count++) { value = Prefs.getString("plug-in" + (count/10)%10 + count%10); if (value==null) break; char firstChar = value.charAt(0); if (firstChar=='-') pluginsMenu.addSeparator(); else if (firstChar=='>') { 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[] pluginList = getPlugins(); String[] pluginsList2 = 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 && pluginList!=null) { // does this plugin exist? if (pluginsList2==null) pluginsList2 = getStrippedPlugins(pluginList); for (int i=0; i<pluginsList2.length; i++) { if (className.startsWith(pluginsList2[i])) { found = true; break; } } } if (found && menu!=pluginsMenu) { addPluginItem(menu, value); pluginsPrefs.addElement(prefsValue); if (className.endsWith("\")")) { // remove any argument int argStart = className.lastIndexOf("(\""); if (argStart>0) className = className.substring(0, argStart); } skipList.put(className, ""); } } if (pluginList!=null) { for (int i=0; i<pluginList.length; i++) { if (!skipList.containsKey(pluginList[i])) installUserPlugin(pluginList[i]); } } installJarPlugins(); installMacros(); } /** Installs macro files that are located in the plugins folder and have a "_" in their name. */ void installMacros() { if (macroFiles==null) return; for (int i=0; i<macroFiles.size(); i++) { String name = (String)macroFiles.elementAt(i); installMacro(name); } } /** Installs a macro in the Plugins menu, or submenu, with with underscores in the file name replaced by spaces. */ void installMacro(String name) { Menu menu = pluginsMenu; String dir = null; int slashIndex = name.indexOf('/'); if (slashIndex>0) { dir = name.substring(0, slashIndex); name = name.substring(slashIndex+1, name.length()); menu = getPluginsSubmenu(dir); slashIndex = name.indexOf('/'); if (slashIndex>0) { String dir2 = name.substring(0, slashIndex); name = name.substring(slashIndex+1, name.length()); String menuName = "Plugins>"+dir+">"+dir2; menu = getMenu(menuName); dir += File.separator+dir2; } } 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<menu.getItemCount(); i++) { if (label.compareTo(menu.getItem(i).getLabel())<0) { menu.insert(item, i); return; } } menu.add(item); } public static String getJarFileForMenuEntry(String menuEntry) { if (instance == null) return null; return (String)instance.menuEntry2jarFile.get(menuEntry); } /** Install plugins located in JAR files. */ void installJarPlugins() { if (jarFiles==null) return; installingJars = true; for (int i=0; i<jarFiles.size(); i++) { isJarErrorHeading = false; String jar = (String)jarFiles.elementAt(i); InputStream is = getConfigurationFile(jar); if (is==null) continue; int maxEntries = 100; String[] entries = new String[maxEntries]; int nEntries=0; LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is)); try { while(true) { String s = lnr.readLine(); if (s==null || nEntries==maxEntries-1) break; if (s.length()>=3 && !s.startsWith("#")) entries[nEntries++] = s; } } catch (IOException e) {} finally { try {if (lnr!=null) lnr.close();} catch (IOException e) {} } for (int j=0; j<nEntries; j++) installJarPlugin(jar, entries[j]); } } /** 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; } String menuEntry = s; if (s.startsWith("\"")) { int quote = s.indexOf('"', 1); menuEntry = quote<0?s.substring(1):s.substring(1, quote); } else { int comma = s.indexOf(','); if (comma > 0) menuEntry = s.substring(0, comma); } if (duplicateCommand) { if (jarError==null) jarError = ""; addJarErrorHeading(jar); String jar2 = (String)menuEntry2jarFile.get(menuEntry); if (jar2 != null && jar2.startsWith(pluginsPath)) jar2 = jar2.substring(pluginsPath.length()); jarError += " Duplicate command: " + s + (jar2 != null ? " (already in " + jar2 + ")" : "") + "\n"; } else menuEntry2jarFile.put(menuEntry, jar); 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; i<count; i++) { MenuItem mi = menu.getItem(i); String label = mi.getLabel(); //IJ.log(i+ " "+itemLabel+" "+label + " "+(itemLabel.compareTo(label))); if (itemLabel.compareTo(label)<0) { menu.insert(item, i); inserted = true; break; } } if (!inserted) menu.add(item); } static void addSeparator(Menu menu) { menu.addSeparator(); } /** Opens the configuration file ("plugins.config") from a JAR file and returns it as an InputStream. */ InputStream getConfigurationFile(String jar) { try { ZipFile jarFile = new ZipFile(jar); Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); if (entry.getName().endsWith("plugins.config")) return jarFile.getInputStream(entry); } } catch (Throwable e) { IJ.log(jar+": "+e); } return autoGenerateConfigFile(jar); } /** Creates a configuration file for JAR/ZIP files that do not have one. */ InputStream autoGenerateConfigFile(String jar) { StringBuffer sb = null; try { ZipFile jarFile = new ZipFile(jar); Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { ZipEntry entry = (ZipEntry) entries.nextElement(); String name = entry.getName(); if (name.endsWith(".class") && name.indexOf("_")>0 && name.indexOf("$")==-1 && name.indexOf("/_")==-1 && !name.startsWith("_")) { if (Character.isLowerCase(name.charAt(0))&&name.indexOf("/")!=-1) continue; 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('/', '.'); //if (className.indexOf(".")==-1 || Character.isUpperCase(className.charAt(0))) sb.append(plugins + ", \""+name+"\", "+className+"\n"); } } } catch (Throwable e) { IJ.log(jar+": "+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<plugins2.length; i++) { plugins2[i] = plugins[i]; slashPos = plugins2[i].lastIndexOf('/'); if (slashPos>=0) plugins2[i] = plugins[i].substring(slashPos+1,plugins2[i].length()); } return plugins2; } void setupPluginsAndMacrosPaths() { pluginsPath = macrosPath = null; String homeDir = Prefs.getHomeDir(); if (homeDir==null) return; 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())) { pluginsPath = null; return; } } /** Returns a list of the plugins in the plugins menu. */ public static synchronized String[] getPlugins() { File f = pluginsPath!=null?new File(pluginsPath):null; if (f==null || (f!=null && !f.isDirectory())) return null; String[] list = f.list(); if (list==null) return null; Vector v = new Vector(); jarFiles = null; macroFiles = null; for (int i=0; i<list.length; i++) { String name = list[i]; boolean isClassFile = name.endsWith(".class"); boolean hasUnderscore = name.indexOf('_')>=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<list.length; i++) { String name = list[i]; boolean hasUnderscore = name.indexOf('_')>=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++; } else { File f2 = new File(f, name); if (f2.isDirectory()) installSubdirectorMacros(f2, dir+name); } } if (Prefs.moveToMisc && classCount==1 && otherCount==0 && dir.indexOf("_")==-1) v.setElementAt("Miscellaneous/" + className, v.size() - 1); } /** Installs macros and scripts located in subdirectories. */ private static void installSubdirectorMacros(File f2, String dir) { if (dir.endsWith("Launchers")) return; String[] list = f2.list(); if (list==null) return; for (int i=0; i<list.length; i++) { String name = list[i]; boolean hasUnderscore = name.indexOf('_')>=0; if ((hasUnderscore&&name.endsWith(".txt")) || name.endsWith(".ijm") || name.endsWith(".js")) { if (macroFiles==null) macroFiles = new Vector(); macroFiles.addElement(dir+"/"+name); } } } /** 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() && !ip.isPseudoColorLut()) { type = ImagePlus.COLOR_256; 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<nItems; i++) { CheckboxMenuItem item = (CheckboxMenuItem)window.getItem(i); item.setState(i==index); } } catch (Exception e) {} } static boolean isColorLut(ImagePlus imp) { ImageProcessor ip = imp.getProcessor(); IndexColorModel cm = (IndexColorModel)ip.getColorModel(); if (cm==null) return false; int mapSize = cm.getMapSize(); byte[] reds = new byte[mapSize]; byte[] greens = new byte[mapSize]; byte[] blues = new byte[mapSize]; cm.getReds(reds); cm.getGreens(greens); cm.getBlues(blues); boolean isColor = false; for (int i=0; i<mapSize; i++) { if ((reds[i] != greens[i]) || (greens[i] != blues[i])) { isColor = true; break; } } return isColor; } /** Returns the path to the user plugins directory or null if the plugins directory was not found. */ public static String getPlugInsPath() { return pluginsPath; } /** Returns the path to the macros directory or null if the macros directory was not found. */ public static String getMacrosPath() { return macrosPath; } /** Returns the hashtable that associates commands with plugins. */ public static Hashtable getCommands() { return pluginsTable; } /** Returns the hashtable that associates shortcuts with commands. The keys in the hashtable are Integer keycodes, or keycode+200 for uppercase. */ public static Hashtable getShortcuts() { return shortcuts; } /** Returns the hashtable that associates keyboard shortcuts with macros. The keys in the hashtable are Integer keycodes, or keycode+200 for uppercase. */ public static Hashtable getMacroShortcuts() { if (macroShortcuts==null) macroShortcuts = new Hashtable(); return macroShortcuts; } /** Inserts one item (a non-image window) into the Window menu. */ static synchronized void insertWindowMenuItem(Frame win) { if (ij==null || win==null) return; CheckboxMenuItem item = new CheckboxMenuItem(win.getTitle()); item.addItemListener(ij); int index = WINDOW_MENU_ITEMS+windowMenuItems2; if (windowMenuItems2>=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<window.getItemCount()) { window.remove(WINDOW_MENU_ITEMS+index); if (index<windowMenuItems2) { windowMenuItems2--; if (windowMenuItems2==1) { window.remove(WINDOW_MENU_ITEMS); windowMenuItems2 = 0; } } } } catch (Exception e) {} } /** Changes the name of an item in the Window menu. */ public static synchronized void updateWindowMenuItem(String oldLabel, String newLabel) { if (oldLabel==null || oldLabel.equals(newLabel)) return; int first = WINDOW_MENU_ITEMS; int last = window.getItemCount()-1; //IJ.write("updateWindowMenuItem: "+" "+first+" "+last+" "+oldLabel+" "+newLabel); try { // workaround for Linux/Java 5.0/bug for (int i=first; i<=last; i++) { MenuItem item = window.getItem(i); //IJ.write(i+" "+item.getLabel()+" "+newLabel); String label = item.getLabel(); if (item!=null && label.startsWith(oldLabel)) { if (label.endsWith("K")) { int index = label.lastIndexOf(' '); if (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; i<count; ) { if (openRecentMenu.getItem(i).getLabel().equals(path)) { openRecentMenu.remove(i); count--; } else i++; } if (count==MAX_OPEN_RECENT_ITEMS) openRecentMenu.remove(MAX_OPEN_RECENT_ITEMS-1); MenuItem item = new MenuItem(path); openRecentMenu.insert(item, 0); item.addActionListener(ij); } public static PopupMenu getPopupMenu() { return popup; } public static Menu getSaveAsMenu() { return saveAsMenu; } /** Adds a plugin based command to the end of a specified menu. * @param plugin the plugin (e.g. "Inverter_", "Inverter_("arg")") * @param menuCode PLUGINS_MENU, IMPORT_MENU, SAVE_AS_MENU or HOT_KEYS * @param command the menu item label (set to "" to uninstall) * @param shortcut the keyboard shortcut (e.g. "y", "Y", "F1") * @param ij ImageJ (the action listener) * * @return returns an error code(NORMAL_RETURN,COMMAND_IN_USE_ERROR, etc.) */ public static int installPlugin(String plugin, char menuCode, String command, String shortcut, ImageJ ij) { if (command.equals("")) { //uninstall //Object o = pluginsPrefs.remove(plugin); //if (o==null) // return NOT_INSTALLED; //else return NORMAL_RETURN; } if (commandInUse(command)) return COMMAND_IN_USE; if (!validShortcut(shortcut)) return INVALID_SHORTCUT; if (shortcutInUse(shortcut)) return SHORTCUT_IN_USE; Menu menu; switch (menuCode) { case PLUGINS_MENU: 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; 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<n; i++) { String key = ""+i; if (key.length()==1) key = "0"+key; key = "recent"+key; prefs.put(key, openRecentMenu.getItem(i).getLabel()); } prefs.put(Prefs.MENU_SIZE, Integer.toString(fontSize)); } public static void updateImageJMenus() { jarFiles = macroFiles = null; Menus m = new Menus(IJ.getInstance(), IJ.getApplet()); String err = m.addMenuBar(); if (err!=null) IJ.error(err); IJ.setClassLoader(null); IJ.runPlugIn("ij.plugin.ClassChecker", ""); IJ.showStatus("Menus updated: "+m.nPlugins + " commands, " + m.nMacros + " macros"); } }