|
Menus |
|
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 static Hashtable demoImagesTable = new Hashtable(); private static String pluginsPath, macrosPath; private static Menu pluginsMenu, importMenu, saveAsMenu, shortcutsMenu, aboutMenu, filtersMenu, toolsMenu, utilitiesMenu, macrosMenu, optionsMenu; private static Hashtable pluginsTable; static Menu window, openRecentMenu; int nPlugins, nMacros; private static Hashtable shortcuts = new Hashtable(); private static Hashtable macroShortcuts; private static Vector pluginsPrefs = new Vector(); // commands saved in IJ_Prefs static int windowMenuItems2; // non-image windows listed in Window menu + separator private static String error; private String jarError; private String pluginError; private boolean isJarErrorHeading; private 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 int importCount, saveAsCount, toolsCount, optionsCount; private static Hashtable menusTable; // Submenus of Plugins menu private int userPluginsIndex; // First user plugin or submenu in Plugins menu private boolean addSorted; private static int fontSize = Prefs.getInt(Prefs.MENU_SIZE, 14); private static Font menuFont; static boolean jnlp; // true when using Java WebStart Menus(ImageJ ijInstance, Applet appletInstance) { ij = ijInstance; applet = appletInstance; } String addMenuBar() { error = null; pluginsTable = new Hashtable(); Menu file = new Menu("File"); addSubMenu(file, "New"); addPlugInItem(file, "Open...", "ij.plugin.Commands(\"open\")", KeyEvent.VK_O, false); addPlugInItem(file, "Open Next", "ij.plugin.NextImageOpener", KeyEvent.VK_O, true); addSubMenu(file, "Open Samples"); addOpenRecentSubMenu(file); importMenu = addSubMenu(file, "Import"); 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 = addSubMenu(file, "Save As"); 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); file.addSeparator(); addPlugInItem(file, "Quit", "ij.plugin.Commands(\"quit\")", 0, false); Menu edit = new Menu("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(); addSubMenu(edit, "Selection"); optionsMenu = addSubMenu(edit, "Options"); Menu image = new Menu("Image"); Menu imageType = new Menu("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(); addSubMenu(image, "Adjust"); addPlugInItem(image, "Show Info...", "ij.plugin.filter.Info", KeyEvent.VK_I, false); addPlugInItem(image, "Properties...", "ij.plugin.filter.ImageProperties", KeyEvent.VK_P, true); //addSubMenu(image, "Benchmarks"); addSubMenu(image, "Color"); addSubMenu(image, "Stacks"); 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); addSubMenu(image, "Rotate"); addSubMenu(image, "Zoom"); image.addSeparator(); addSubMenu(image, "Lookup Tables"); Menu process = new Menu("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); addSubMenu(process, "Noise"); addSubMenu(process, "Shadows"); addSubMenu(process, "Binary"); addSubMenu(process, "Math"); addSubMenu(process, "FFT"); filtersMenu = addSubMenu(process, "Filters"); 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 analyze = new Menu("Analyze"); addPlugInItem(analyze, "Measure", "ij.plugin.filter.Analyzer", KeyEvent.VK_M, false); addPlugInItem(analyze, "Analyze Particles...", "ij.plugin.filter.ParticleAnalyzer", 0, false); addPlugInItem(analyze, "Summarize", "ij.plugin.filter.Analyzer(\"sum\")", 0, false); addPlugInItem(analyze, "Distribution...", "ij.plugin.Distribution", 0, false); addPlugInItem(analyze, "Label", "ij.plugin.filter.Filler(\"label\")", 0, false); addPlugInItem(analyze, "Clear Results", "ij.plugin.filter.Analyzer(\"clear\")", 0, false); addPlugInItem(analyze, "Set Measurements...", "ij.plugin.filter.Analyzer(\"set\")", 0, false); analyze.addSeparator(); addPlugInItem(analyze, "Set Scale...", "ij.plugin.filter.ScaleDialog", 0, false); addPlugInItem(analyze, "Calibrate...", "ij.plugin.filter.Calibrator", 0, false); addPlugInItem(analyze, "Histogram", "ij.plugin.Histogram", KeyEvent.VK_H, false); addPlugInItem(analyze, "Plot Profile", "ij.plugin.filter.Profiler(\"plot\")", KeyEvent.VK_K, false); addPlugInItem(analyze, "Surface Plot...", "ij.plugin.SurfacePlotter", 0, false); addSubMenu(analyze, "Gels"); toolsMenu = addSubMenu(analyze, "Tools"); window = new Menu("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 = new Menu("Help"); addPlugInItem(help, "ImageJ Website...", "ij.plugin.BrowserLauncher", 0, false); addPlugInItem(help, "ImageJ News...", "ij.plugin.BrowserLauncher(\"http://rsb.info.nih.gov/ij/notes.html\")", 0, false); addPlugInItem(help, "Documentation...", "ij.plugin.BrowserLauncher(\"http://rsb.info.nih.gov/ij/docs\")", 0, false); addPlugInItem(help, "Installation...", "ij.plugin.SimpleCommands(\"install\")", 0, false); addPlugInItem(help, "Search Website...", "ij.plugin.BrowserLauncher(\"http://rsb.info.nih.gov/ij/search.html\")", 0, false); addPlugInItem(help, "List Archives...", "ij.plugin.BrowserLauncher(\"https://list.nih.gov/archives/imagej.html\")", 0, false); help.addSeparator(); addPlugInItem(help, "Plugins...", "ij.plugin.BrowserLauncher(\"http://rsb.info.nih.gov/ij/plugins\")", 0, false); addPlugInItem(help, "Macros...", "ij.plugin.BrowserLauncher(\"http://rsb.info.nih.gov/ij/macros/\")", 0, false); addPlugInItem(help, "Source Code...", "ij.plugin.BrowserLauncher(\"http://rsb.info.nih.gov/ij/developer/source/\")", 0, false); addPlugInItem(help, "Macro Language...", "ij.plugin.BrowserLauncher(\"http://rsb.info.nih.gov/ij/developer/macro/macros.html\")", 0, false); addPlugInItem(help, "Macro Functions...", "ij.plugin.BrowserLauncher(\"http://rsb.info.nih.gov/ij/developer/macro/functions.html\")", 0, false); help.addSeparator(); aboutMenu = addSubMenu(help, "About Plugins"); addPlugInItem(help, "About ImageJ...", "ij.plugin.AboutBox", 0, false); addPluginsMenu(); if (applet==null) installPlugins(); mbar = new MenuBar(); if (fontSize!=0) mbar.setFont(getFont()); mbar.add(file); mbar.add(edit); mbar.add(image); mbar.add(process); mbar.add(analyze); mbar.add(pluginsMenu); mbar.add(window); mbar.setHelpMenu(help); 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 = new Menu("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); } 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; } 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; } 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; 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++; } } } 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"); 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 = 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 = importMenu; break; case SAVE_AS_MENU: menu = saveAsMenu; break; case SHORTCUTS_MENU: menu = shortcutsMenu; break; case ABOUT_MENU: menu = aboutMenu; break; case FILTERS_MENU: menu = filtersMenu; break; case TOOLS_MENU: menu = toolsMenu; 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; i<plugins2.length; i++) { if (className.startsWith(plugins2[i])) { found = true; break; } } } if (found) { 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 (plugins!=null) { for (int i=0; i<plugins.length; i++) { if (!skipList.containsKey(plugins[i])) installUserPlugin(plugins[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); } String command = name.replace('_',' '); 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++; } /** Inserts 'item' into 'menu' in alphanumeric order. */ void addOrdered(Menu menu, MenuItem item) { if (menu==pluginsMenu) {menu.add(item); return;} String label = item.getLabel(); for (int i=0; i<menu.getItemCount(); i++) { if (label.compareTo(menu.getItem(i).getLabel())<0) { menu.insert(item, i); return; } } menu.add(item); } /** 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; LineNumberReader lnr = new LineNumberReader(new InputStreamReader(is)); try { while(true) { String s = lnr.readLine(); if (s==null) break; installJarPlugin(jar, s); } } catch (IOException e) {} finally { try {if (lnr!=null) lnr.close();} catch (IOException e) {} } } } /** Install a plugin located in a JAR file. */ void installJarPlugin(String jar, String s) { //IJ.log(s); if (s.length()<3) return; char firstChar = s.charAt(0); if (firstChar=='#') return; 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 (firstChar=='"' || s.startsWith("Plugins")) { String name = getSubmenuName(jar); if (name!=null) menu = getPluginsSubmenu(name); else menu = pluginsMenu; addSorted = true; } else if (s.startsWith("File>Import")) { menu = importMenu; if (importCount==0) addSeparator(menu); importCount++; } else if (s.startsWith("File>Save")) { menu = saveAsMenu; if (saveAsCount==0) addSeparator(menu); saveAsCount++; } else if (s.startsWith("Analyze>Tools")) { menu = toolsMenu; if (toolsCount==0) addSeparator(menu); toolsCount++; } else if (s.startsWith("Help>About")) { menu = aboutMenu; } else if (s.startsWith("Edit>Options")) { menu = optionsMenu; if (optionsCount==0) addSeparator(menu); optionsCount++; } else { if (jarError==null) jarError = ""; addJarErrorHeading(jar); jarError += " Invalid menu: " + s + "\n"; return; } int firstQuote = s.indexOf('"'); if (firstQuote==-1) return; s = s.substring(firstQuote, s.length()); // remove menu if (menu!=null) { 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; } } Menu getPluginsSubmenu(String submenuName) { if (menusTable!=null) { Menu menu = (Menu)menusTable.get(submenuName); if (menu!=null) return menu; } Menu menu = new Menu(submenuName); //pluginsMenu.add(menu); addItemSorted(pluginsMenu, menu, userPluginsIndex); if (menusTable==null) menusTable = new Hashtable(); menusTable.put(submenuName, menu); //IJ.log("getPluginsSubmenu: "+submenuName); return menu; } String getSubmenuName(String jarPath) { //IJ.log("getSubmenuName: \n"+jarPath+"\n"+pluginsPath); 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; } 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); } void addSeparator(Menu menu) { menu.addSeparator(); } /** Opens the configuration file ("plugins.txt") 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 (Exception 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 (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<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; } /** 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<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"))) { 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. */ 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 += "/"; 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); //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); } else if (hasUnderscore && (name.endsWith(".txt")||name.endsWith(".ijm"))) { if (macroFiles==null) macroFiles = new Vector(); macroFiles.addElement(dir + name); } } } static String submenuName; static Menu submenu; /** Installs a plugin in the Plugins menu using the class name, with underscores replaced by spaces, as the command. */ void installUserPlugin(String className) { Menu menu = pluginsMenu; int slashIndex = className.indexOf('/'); String command = className; if (slashIndex>0) { String dir = className.substring(0, slashIndex); command = className.substring(slashIndex+1, className.length()); //className = className.replace('/', '.'); if (submenu==null || !submenuName.equals(dir)) { submenuName = dir; submenu = new Menu(submenuName); pluginsMenu.add(submenu); if (menusTable==null) menusTable = new Hashtable(); menusTable.put(submenuName, submenu); } menu = submenu; //IJ.write(dir + " " + className); } command = command.replace('_',' '); command.trim(); if (pluginsTable.get(command)!=null) // duplicate command? command = command + " Plugin"; MenuItem item = new MenuItem(command); menu.add(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; } 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<nItems; i++) { CheckboxMenuItem item = (CheckboxMenuItem)window.getItem(i); item.setState(i==index); } } catch (NullPointerException 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; } /** Returns the hashtable that associates menu names with menus. */ //public static Hashtable getMenus() { // return menusTable; //} /** 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; 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; } } } } /** Changes the name of an item in the Window menu. */ public static synchronized void updateWindowMenuItem(String oldLabel, String newLabel) { if (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(); if (count>0 && openRecentMenu.getItem(0).getLabel().equals(path)) return; 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; } /** 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 = importMenu; break; case SAVE_AS_MENU: menu = saveAsMenu; break; case SHORTCUTS_MENU: menu = shortcutsMenu; break; case ABOUT_MENU: menu = aboutMenu; break; case FILTERS_MENU: menu = filtersMenu; break; case TOOLS_MENU: menu = toolsMenu; 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)); } }
|
Menus |
|