package ij.plugin.frame; import java.awt.*; import java.awt.event.*; import java.io.*; import java.util.*; import java.awt.datatransfer.*; import ij.*; import ij.gui.*; import ij.util.Tools; import ij.text.*; import ij.macro.*; import ij.plugin.MacroInstaller; import ij.plugin.NewPlugin; import ij.io.SaveDialog; /** This is a simple TextArea based editor for editing and compiling plugins. */ public class Editor extends PlugInFrame implements ActionListener, ItemListener, TextListener, ClipboardOwner, MacroConstants { /** ImportPackage statements added in front of scripts. Contains no newlines so that lines numbers in error messages are not changed. */ public static String JavaScriptIncludes = "importPackage(Packages.ij);"+ "importPackage(Packages.ij.gui);"+ "importPackage(Packages.ij.process);"+ "importPackage(Packages.ij.measure);"+ "importPackage(Packages.ij.util);"+ "importPackage(Packages.ij.plugin);"+ "importPackage(Packages.ij.io);"+ "importPackage(Packages.ij.plugin.filter);"+ "importPackage(Packages.ij.plugin.frame);"+ "importPackage(java.lang);"+ "importPackage(java.awt);"+ "importPackage(java.awt.image);"+ "importPackage(java.awt.geom);"+ "importPackage(java.util);"+ "importPackage(java.io);"+ "function print(s) {IJ.log(s);};"; public static String JS_NOT_FOUND = "JavaScript.jar was not found in the plugins\nfolder. It can be downloaded from:\n \n"+IJ.URL+"/download/tools/JavaScript.jar"; public static final int MAX_SIZE=28000, XINC=10, YINC=18; public static final int MONOSPACED=1, MENU_BAR=2; public static final int MACROS_MENU_ITEMS = 8; static final String FONT_SIZE = "editor.font.size"; static final String FONT_MONO= "editor.font.mono"; static final String CASE_SENSITIVE= "editor.case-sensitive"; static final String DEFAULT_DIR= "editor.dir"; private TextArea ta; private String path; private boolean changes; private static String searchString = ""; private static boolean caseSensitive = Prefs.get(CASE_SENSITIVE, true); private static int lineNumber = 1; private static int xoffset, yoffset; private static int nWindows; private Menu fileMenu, editMenu; private Properties p = new Properties(); private int[] macroStarts; private String[] macroNames; private MenuBar mb; private Menu macrosMenu; private int nMacros; private Program pgm; private int eventCount; private String shortcutsInUse; private int inUseCount; private MacroInstaller installer; private static String defaultDir = Prefs.get(DEFAULT_DIR, null);; private boolean dontShowWindow; private int[] sizes = {9, 10, 11, 12, 13, 14, 16, 18, 20, 24, 36, 48, 60, 72}; private int fontSize = (int)Prefs.get(FONT_SIZE, 6); // defaults to 16-point private CheckboxMenuItem monospaced; private static boolean wholeWords; private boolean isMacroWindow; private int debugStart, debugEnd; private static TextWindow debugWindow; private boolean step; private int previousLine; private static Editor instance; private int runToLine; private boolean fixedLineEndings; public Editor() { this(16, 60, 0, MENU_BAR); } public Editor(int rows, int columns, int fontSize, int options) { super("Editor"); WindowManager.addWindow(this); addMenuBar(options); ta = new TextArea(rows, columns); ta.addTextListener(this); if (IJ.isLinux()) ta.setBackground(Color.white); addKeyListener(IJ.getInstance()); // ImageJ handles keyboard shortcuts add(ta); pack(); if (fontSize<0) fontSize = 0; if (fontSize>=sizes.length) fontSize = sizes.length-1; setFont(); positionWindow(); } void addMenuBar(int options) { mb = new MenuBar(); if (Menus.getFontSize()!=0) ; mb.setFont(Menus.getFont()); Menu m = new Menu("File"); m.add(new MenuItem("New...", new MenuShortcut(KeyEvent.VK_N, true))); m.add(new MenuItem("Open...", new MenuShortcut(KeyEvent.VK_O))); m.add(new MenuItem("Save", new MenuShortcut(KeyEvent.VK_S))); m.add(new MenuItem("Save As...")); m.add(new MenuItem("Print...", new MenuShortcut(KeyEvent.VK_P))); m.addActionListener(this); fileMenu = m; mb.add(m); m = new Menu("Edit"); String key = IJ.isMacintosh()?" Cmd ":" Ctrl+"; MenuItem item = new MenuItem("Undo"+key+"Z"); item.setEnabled(false); m.add(item); m.addSeparator(); boolean shortcutsBroken = IJ.isWindows() && (System.getProperty("java.version").indexOf("1.1.8")>=0 ||System.getProperty("java.version").indexOf("1.5.")>=0); if (shortcutsBroken) item = new MenuItem("Cut Ctrl+X"); else item = new MenuItem("Cut",new MenuShortcut(KeyEvent.VK_X)); m.add(item); if (shortcutsBroken) item = new MenuItem("Copy Ctrl+C"); else item = new MenuItem("Copy", new MenuShortcut(KeyEvent.VK_C)); m.add(item); if (shortcutsBroken) item = new MenuItem("Paste Ctrl+V"); else item = new MenuItem("Paste",new MenuShortcut(KeyEvent.VK_V)); m.add(item); m.addSeparator(); m.add(new MenuItem("Find...", new MenuShortcut(KeyEvent.VK_F))); m.add(new MenuItem("Find Next", new MenuShortcut(KeyEvent.VK_G))); m.add(new MenuItem("Go to Line...", new MenuShortcut(KeyEvent.VK_L))); m.addSeparator(); m.add(new MenuItem("Select All", new MenuShortcut(KeyEvent.VK_A))); m.add(new MenuItem("Zap Gremlins")); m.add(new MenuItem("Copy to Image Info")); m.addActionListener(this); mb.add(m); editMenu = m; if ((options&MENU_BAR)!=0) setMenuBar(mb); m = new Menu("Font"); m.add(new MenuItem("Make Text Smaller", new MenuShortcut(KeyEvent.VK_N))); m.add(new MenuItem("Make Text Larger", new MenuShortcut(KeyEvent.VK_M))); m.addSeparator(); monospaced = new CheckboxMenuItem("Monospaced Font", Prefs.get(FONT_MONO, false)); if ((options&MONOSPACED)!=0) monospaced.setState(true); monospaced.addItemListener(this); m.add(monospaced); m.add(new MenuItem("Save Settings")); m.addActionListener(this); mb.add(m); } public void positionWindow() { Dimension screen = IJ.getScreenSize(); Dimension window = getSize(); if (window.width==0) return; int left = screen.width/2-window.width/2; int top = (screen.height-window.height)/4; if (top<0) top = 0; if (nWindows<=0 || xoffset>8*XINC) {xoffset=0; yoffset=0;} setLocation(left+xoffset, top+yoffset); xoffset+=XINC; yoffset+=YINC; nWindows++; } void setWindowTitle(String title) { Menus.updateWindowMenuItem(getTitle(), title); setTitle(title); } public void create(String name, String text) { if (text!=null && text.length()>0) fixedLineEndings = true; ta.append(text); if (IJ.isMacOSX()) IJ.wait(25); // needed to get setCaretPosition() on OS X ta.setCaretPosition(0); setWindowTitle(name); boolean macroExtension = name.endsWith(".txt") || name.endsWith(".ijm"); if (macroExtension || name.endsWith(".js") || name.indexOf(".")==-1) { macrosMenu = new Menu("Macros"); macrosMenu.add(new MenuItem("Run Macro", new MenuShortcut(KeyEvent.VK_R))); macrosMenu.add(new MenuItem("Evaluate Line", new MenuShortcut(KeyEvent.VK_Y))); macrosMenu.add(new MenuItem("Abort Macro")); macrosMenu.add(new MenuItem("Install Macros", new MenuShortcut(KeyEvent.VK_I))); macrosMenu.add(new MenuItem("Function Finder...", new MenuShortcut(KeyEvent.VK_F, true))); macrosMenu.addSeparator(); macrosMenu.add(new MenuItem("Evaluate JavaScript", new MenuShortcut(KeyEvent.VK_J, false))); macrosMenu.addSeparator(); // MACROS_MENU_ITEMS must be updated if items are added to this menu macrosMenu.addActionListener(this); mb.add(macrosMenu); if (!name.endsWith(".js")) { Menu debugMenu = new Menu("Debug"); debugMenu.add(new MenuItem("Debug Macro", new MenuShortcut(KeyEvent.VK_D))); debugMenu.add(new MenuItem("Step", new MenuShortcut(KeyEvent.VK_E))); debugMenu.add(new MenuItem("Trace", new MenuShortcut(KeyEvent.VK_T))); debugMenu.add(new MenuItem("Fast Trace", new MenuShortcut(KeyEvent.VK_T,true))); debugMenu.add(new MenuItem("Run")); debugMenu.add(new MenuItem("Run to Insertion Point", new MenuShortcut(KeyEvent.VK_E, true))); debugMenu.add(new MenuItem("Abort")); debugMenu.addActionListener(this); mb.add(debugMenu); } if (macroExtension && text.indexOf("macro ")!=-1) installMacros(text, false); } else { fileMenu.addSeparator(); fileMenu.add(new MenuItem("Compile and Run", new MenuShortcut(KeyEvent.VK_R))); } if (IJ.getInstance()!=null && !dontShowWindow) show(); if (dontShowWindow) { dispose(); dontShowWindow = false; } WindowManager.setWindow(this); changes = false; } public void createMacro(String name, String text) { create(name, text); } void installMacros(String text, boolean installInPluginsMenu) { String functions = Interpreter.getAdditionalFunctions(); if (functions!=null && text!=null) { if (!(text.endsWith("\n") || functions.startsWith("\n"))) text = text + "\n" + functions; else text = text + functions; } installer = new MacroInstaller(); installer.setFileName(getTitle()); int nShortcutsOrTools = installer.install(text, macrosMenu); if (installInPluginsMenu || nShortcutsOrTools>0) installer.install(null); dontShowWindow = installer.isAutoRunAndHide(); } public void open(String dir, String name) { path = dir+name; File file = new File(path); try { StringBuffer sb = new StringBuffer(5000); BufferedReader r = new BufferedReader(new FileReader(file)); while (true) { String s=r.readLine(); if (s==null) break; else sb.append(s+"\n"); } r.close(); create(name, new String(sb)); changes = false; } catch (Exception e) { IJ.handleException(e); return; } } public String getText() { if (ta==null) return ""; else return ta.getText(); } public TextArea getTextArea() { return ta; } public void display(String title, String text) { ta.selectAll(); ta.replaceRange(text, ta.getSelectionStart(), ta.getSelectionEnd()); ta.setCaretPosition(0); setWindowTitle(title); changes = false; if (IJ.getInstance()!=null) show(); WindowManager.setWindow(this); } void save() { if (path==null) { saveAs(); return; } File f = new File(path); if (f.exists() && !f.canWrite()) { IJ.showMessage("Editor", "Unable to save because file is write-protected. \n \n" + path); return; } String text = ta.getText(); char[] chars = new char[text.length()]; text.getChars(0, text.length(), chars, 0); try { BufferedReader br = new BufferedReader(new CharArrayReader(chars)); BufferedWriter bw = new BufferedWriter(new FileWriter(path)); while (true) { String s = br.readLine(); if (s==null) break; bw.write(s, 0, s.length()); bw.newLine(); } bw.close(); IJ.showStatus(text.length()+" chars saved to " + path); changes = false; } catch (IOException e) {} } void compileAndRun() { if (path==null) saveAs(); if (path!=null) { save(); String text = ta.getText(); if (text.contains("implements PlugInFilter") && text.contains("IJ.run(")) IJ.log("Plugins that call IJ.run() should probably implement PlugIns, not PlugInFilters."); IJ.runPlugIn("ij.plugin.Compiler", path); } } final void runMacro(boolean debug) { if (getTitle().endsWith(".js")) {evaluateJavaScript(); return;} int start = ta.getSelectionStart(); int end = ta.getSelectionEnd(); String text; if (start==end) text = ta.getText(); else text = ta.getSelectedText(); new MacroRunner(text, debug?this:null); } void evaluateJavaScript() { if (!getTitle().endsWith(".js")) setTitle(SaveDialog.setExtension(getTitle(), ".js")); int start = ta.getSelectionStart(); int end = ta.getSelectionEnd(); String text; if (start==end) text = ta.getText(); else text = ta.getSelectedText(); if (text.equals("")) return; text = getJSPrefix("") + text; if (IJ.isJava16() && !(IJ.isMacOSX()&&!IJ.is64Bit())) IJ.runPlugIn("JavaScriptEvaluator", text); else { Object js = IJ.runPlugIn("JavaScript", text); if (js==null) IJ.error(JS_NOT_FOUND); } } void evaluateLine() { int start = ta.getSelectionStart(); int end = ta.getSelectionEnd(); if (end>start) {runMacro(false); return;} String text = ta.getText(); while (start>0) { start--; if (text.charAt(start)=='\n') {start++; break;} } while (end<text.length()-1) { end++; if (text.charAt(end)=='\n') break; } ta.setSelectionStart(start); ta.setSelectionEnd(end); runMacro(false); } void print () { PrintJob pjob = Toolkit.getDefaultToolkit().getPrintJob(this, "Cool Stuff", p); if (pjob != null) { Graphics pg = pjob.getGraphics( ); if (pg != null) { String s = ta.getText(); printString(pjob, pg, s); pg.dispose( ); } pjob.end( ); } } void printString (PrintJob pjob, Graphics pg, String s) { int pageNum = 1; int linesForThisPage = 0; int linesForThisJob = 0; int topMargin = 30; int leftMargin = 30; int bottomMargin = 30; if (!(pg instanceof PrintGraphics)) throw new IllegalArgumentException ("Graphics contextt not PrintGraphics"); if (IJ.isMacintosh()) { topMargin = 0; leftMargin = 0; bottomMargin = 0; } StringReader sr = new StringReader (s); LineNumberReader lnr = new LineNumberReader (sr); String nextLine; int pageHeight = pjob.getPageDimension().height - bottomMargin; Font helv = new Font(getFontName(), Font.PLAIN, 10); pg.setFont (helv); FontMetrics fm = pg.getFontMetrics(helv); int fontHeight = fm.getHeight(); int fontDescent = fm.getDescent(); int curHeight = topMargin; try { do { nextLine = lnr.readLine(); if (nextLine != null) { nextLine = detabLine(nextLine); if ((curHeight + fontHeight) > pageHeight) { // New Page pageNum++; linesForThisPage = 0; pg.dispose(); pg = pjob.getGraphics(); if (pg != null) pg.setFont (helv); curHeight = topMargin; } curHeight += fontHeight; if (pg != null) { pg.drawString (nextLine, leftMargin, curHeight - fontDescent); linesForThisPage++; linesForThisJob++; } } } while (nextLine != null); } catch (EOFException eof) { // Fine, ignore } catch (Throwable t) { // Anything else IJ.handleException(t); } } String detabLine(String s) { if (s.indexOf('\t')<0) return s; int tabSize = 4; StringBuffer sb = new StringBuffer((int)(s.length()*1.25)); char c; for (int i=0; i<s.length(); i++) { c = s.charAt(i); if (c=='\t') { for (int j=0; j<tabSize; j++) sb.append(' '); } else sb.append(c); } return sb.toString(); } boolean copy() { String s; s = ta.getSelectedText(); Clipboard clip = getToolkit().getSystemClipboard(); if (clip!=null) { StringSelection cont = new StringSelection(s); clip.setContents(cont,this); return true; } else return false; } void cut() { if (copy()) { int start = ta.getSelectionStart(); int end = ta.getSelectionEnd(); ta.replaceRange("", start, end); if (IJ.isMacOSX()) ta.setCaretPosition(start); } } void paste() { String s; s = ta.getSelectedText(); Clipboard clipboard = getToolkit( ). getSystemClipboard(); Transferable clipData = clipboard.getContents(s); try { s = (String)(clipData.getTransferData(DataFlavor.stringFlavor)); } catch (Exception e) { s = e.toString( ); } if (!fixedLineEndings && IJ.isWindows()) fixLineEndings(); fixedLineEndings = true; int start = ta.getSelectionStart( ); int end = ta.getSelectionEnd( ); ta.replaceRange(s, start, end); if (IJ.isMacOSX()) ta.setCaretPosition(start+s.length()); } void copyToInfo() { ImagePlus imp = WindowManager.getCurrentImage(); if (imp==null) { IJ.noImage(); return; } int start = ta.getSelectionStart(); int end = ta.getSelectionEnd(); String text; if (start==end) text = ta.getText(); else text = ta.getSelectedText(); imp.setProperty("Info", text); } public void actionPerformed(ActionEvent e) { String what = e.getActionCommand(); int flags = e.getModifiers(); boolean altKeyDown = (flags & Event.ALT_MASK)!=0; if (IJ.debugMode) IJ.log("actionPerformed: "+e); if ("Save".equals(what)) save(); else if ("Compile and Run".equals(what)) compileAndRun(); else if ("Run Macro".equals(what)) { if (altKeyDown) { enableDebugging(); runMacro(true); } else runMacro(false); } else if ("Debug Macro".equals(what)) { enableDebugging(); runMacro(true); } else if ("Step".equals(what)) setDebugMode(Interpreter.STEP); else if ("Trace".equals(what)) setDebugMode(Interpreter.TRACE); else if ("Fast Trace".equals(what)) setDebugMode(Interpreter.FAST_TRACE); else if ("Run".equals(what)) setDebugMode(Interpreter.RUN); else if ("Run to Insertion Point".equals(what)) runToInsertionPoint(); else if ("Abort".equals(what) || "Abort Macro".equals(what)) { Interpreter.abort(); IJ.beep(); } else if ("Evaluate Line".equals(what)) evaluateLine(); else if ("Install Macros".equals(what)) installMacros(ta.getText(), true); else if ("Function Finder...".equals(what)) new FunctionFinder(); else if ("Evaluate JavaScript".equals(what)) evaluateJavaScript(); else if ("Print...".equals(what)) print(); else if (what.equals("Paste")) paste(); else if (what.equals("Copy")) copy(); else if (what.equals("Cut")) cut(); else if ("Save As...".equals(what)) saveAs(); else if ("Select All".equals(what)) selectAll(); else if ("Find...".equals(what)) find(null); else if ("Find Next".equals(what)) find(searchString); else if ("Go to Line...".equals(what)) gotoLine(); else if ("Zap Gremlins".equals(what)) zapGremlins(); else if ("Make Text Larger".equals(what)) changeFontSize(true); else if ("Make Text Smaller".equals(what)) changeFontSize(false); else if ("Save Settings".equals(what)) saveSettings(); else if ("New...".equals(what)) IJ.run("Text Window"); else if ("Open...".equals(what)) IJ.open(); else if (what.equals("Copy to Image Info")) copyToInfo(); else { if (altKeyDown) { enableDebugging(); installer.runMacro(what, this); } else installer.runMacro(what, null); } } final void runToInsertionPoint() { Interpreter interp = Interpreter.getInstance(); if (interp==null) IJ.beep(); else { runToLine = getCurrentLine(); //IJ.log("runToLine: "+runToLine); setDebugMode(Interpreter.RUN_TO_CARET); } } final int getCurrentLine() { int pos = ta.getCaretPosition(); int currentLine = 0; String text = ta.getText(); if (IJ.isWindows() && !IJ.isVista()) text = text.replaceAll("\r\n", "\n"); char[] chars = new char[text.length()]; chars = text.toCharArray(); int count=0; int start=0, end=0; int len = chars.length; for (int i=0; i<len; i++) { if (chars[i]=='\n') { count++; start = end; end = i; if (pos>=start && pos<end) { currentLine = count; break; } } } if (currentLine==0 && pos>end) currentLine = count; return currentLine; } final void enableDebugging() { step = true; Interpreter interp = Interpreter.getInstance(); if (interp!=null && interp.getEditor()==this) { interp.abort(); IJ.wait(100); } int start = ta.getSelectionStart(); int end = ta.getSelectionEnd(); if (start==debugStart && end==debugEnd) ta.select(start, start); } final void setDebugMode(int mode) { step = true; Interpreter interp = Interpreter.getInstance(); if (interp!=null) { interp.setEditor(this); interp.setDebugMode(mode); } } public void textValueChanged(TextEvent evt) { if (isMacroWindow) return; // first few textValueChanged events may be bogus eventCount++; if (eventCount>2 || !IJ.isMacOSX() && eventCount>1) changes = true; if (IJ.isMacOSX()) // screen update bug work around ta.setCaretPosition(ta.getCaretPosition()); } public void itemStateChanged(ItemEvent e) { CheckboxMenuItem item = (CheckboxMenuItem)e.getSource(); setFont(); } /** Override windowActivated in PlugInFrame to prevent Mac menu bar from being installed. */ public void windowActivated(WindowEvent e) { WindowManager.setWindow(this); instance = this; } /** Overrides close() in PlugInFrame. */ public void close() { boolean okayToClose = true; ImageJ ij = IJ.getInstance(); if (!getTitle().equals("Errors") && changes && !IJ.isMacro() && ij!=null) { String msg = "Save changes to \"" + getTitle() + "\"?"; YesNoCancelDialog d = new YesNoCancelDialog(this, "Editor", msg); if (d.cancelPressed()) okayToClose = false; else if (d.yesPressed()) save(); } if (okayToClose) { //setVisible(false); dispose(); WindowManager.removeWindow(this); nWindows--; instance = null; changes = false; } } public void saveAs() { String name1 = getTitle(); if (name1.indexOf(".")==-1) name1 += ".txt"; if (defaultDir==null) { if (name1.endsWith(".txt")||name1.endsWith(".ijm")) defaultDir = Menus.getMacrosPath(); else defaultDir = Menus.getPlugInsPath(); } SaveDialog sd = new SaveDialog("Save As...", defaultDir, name1, null); String name2 = sd.getFileName(); String dir = sd.getDirectory(); if (name2!=null) { if (name2.endsWith(".java")) updateClassName(name1, name2); path = dir+name2; save(); changes = false; setWindowTitle(name2); setDefaultDirectory(dir); if (defaultDir!=null) Prefs.set(DEFAULT_DIR, defaultDir); if (Recorder.record) Recorder.record("saveAs", "Text", path); } } /** Changes a plugins class name to reflect a new file name. */ public void updateClassName(String oldName, String newName) { if (newName.indexOf("_")<0) IJ.showMessage("Plugin Editor", "Plugins without an underscore in their name will not\n" +"be automatically installed when ImageJ is restarted."); if (oldName.equals(newName) || !oldName.endsWith(".java") || !newName.endsWith(".java")) return; oldName = oldName.substring(0,oldName.length()-5); newName = newName.substring(0,newName.length()-5); String text1 = ta.getText(); int index = text1.indexOf("public class "+oldName); if (index<0) return; String text2 = text1.substring(0,index+13)+newName+text1.substring(index+13+oldName.length(),text1.length()); ta.setText(text2); } void find(String s) { if (s==null) { GenericDialog gd = new GenericDialog("Find", this); gd.addStringField("Find: ", searchString, 20); String[] labels = {"Case Sensitive", "Whole Words"}; boolean[] states = {caseSensitive, wholeWords}; //boolean[] states = new boolean[2]; //states[0]=caseSensitive; states[1]=wholeWords; gd.addCheckboxGroup(1, 2, labels, states); gd.showDialog(); if (gd.wasCanceled()) return; s = gd.getNextString(); caseSensitive = gd.getNextBoolean(); wholeWords = gd.getNextBoolean(); Prefs.set(CASE_SENSITIVE, caseSensitive); } if (s.equals("")) return; String text = ta.getText(); String s2 = s; if (!caseSensitive) { text = text.toLowerCase(Locale.US); s = s.toLowerCase(Locale.US); } int index = -1; if (wholeWords) { int position = ta.getCaretPosition()+1; while (true) { index = text.indexOf(s, position); if (index==-1) break; if (isWholeWordMatch(text, s, index)) break; position = index + 1; if (position>=text.length()-1) {index=-1; break;} } } else index = text.indexOf(s, ta.getCaretPosition()+1); searchString = s2; if (index<0) {IJ.beep(); return;} ta.setSelectionStart(index); ta.setSelectionEnd(index+s.length()); } boolean isWholeWordMatch(String text, String word, int index) { char c = index==0?' ':text.charAt(index-1); if (Character.isLetterOrDigit(c) || c=='_') return false; c = index+word.length()>=text.length()?' ':text.charAt(index+word.length()); if (Character.isLetterOrDigit(c) || c=='_') return false; return true; } void gotoLine() { GenericDialog gd = new GenericDialog("Go to Line", this); gd.addNumericField("Go to line number: ", lineNumber, 0); gd.showDialog(); if (gd.wasCanceled()) return; int n = (int)gd.getNextNumber(); if (n<1) return; String text = ta.getText(); char[] chars = new char[text.length()]; chars = text.toCharArray(); int count=1, loc=0; for (int i=0; i<chars.length; i++) { if (chars[i]=='\n') count++; if (count==n) {loc=i+1; break;} } ta.setCaretPosition(loc); lineNumber = n; } void zapGremlins() { String text = ta.getText(); char[] chars = new char[text.length()]; chars = text.toCharArray(); int count=0; boolean inQuotes = false; char quoteChar = 0; for (int i=0; i<chars.length; i++) { char c = chars[i]; if (!inQuotes && (c=='"' || c=='\'')) { inQuotes = true; quoteChar = c; } else { if (inQuotes && (c==quoteChar || c=='\n')) inQuotes = false; } if (!inQuotes && c!='\n' && c!='\t' && (c<32||c>127)) { count++; chars[i] = ' '; //IJ.log(""+(0+c)); } } if (count>0) { text = new String(chars); ta.setText(text); } if (count>0) IJ.showMessage("Zap Gremlins", count+" invalid characters converted to spaces"); else IJ.showMessage("Zap Gremlins", "No invalid characters found"); } void selectAll() { ta.selectAll(); } void changeFontSize(boolean larger) { int in = fontSize; if (larger) { fontSize++; if (fontSize==sizes.length) fontSize = sizes.length-1; } else { fontSize--; if (fontSize<0) fontSize = 0; } IJ.showStatus(sizes[fontSize]+" point"); setFont(); } void saveSettings() { Prefs.set(FONT_SIZE, fontSize); Prefs.set(FONT_MONO, monospaced.getState()); IJ.showStatus("Font settings saved (size="+sizes[fontSize]+", monospaced="+monospaced.getState()+")"); } void setFont() { ta.setFont(new Font(getFontName(), Font.PLAIN, sizes[fontSize])); } String getFontName() { return monospaced.getState()?"Monospaced":"SansSerif"; } public void setFont(Font font) { ta.setFont(font); } public void append(String s) { ta.append(s); } public void setIsMacroWindow(boolean mw) { isMacroWindow = mw; } public static void setDefaultDirectory(String defaultDirectory) { defaultDir = defaultDirectory; if (defaultDir!=null && !(defaultDir.endsWith(File.separator)||defaultDir.endsWith("/"))) defaultDir += File.separator; } //public void keyReleased(KeyEvent e) {} //public void keyTyped(KeyEvent e) {} public void lostOwnership (Clipboard clip, Transferable cont) {} public int debug(Interpreter interp, int mode) { if (IJ.debugMode) IJ.log("debug: "+interp.getLineNumber()+" "+mode+" "+interp); if (mode==Interpreter.RUN) return 0; if (!isVisible()) { // abort macro if user closes window interp.abortMacro(); return 0; } if (!isActive()) toFront(); int n = interp.getLineNumber(); if (n==previousLine) {previousLine=0; return 0;} previousLine = n; if (mode==Interpreter.RUN_TO_CARET) { if (n==runToLine) { mode = Interpreter.STEP; interp.setDebugMode(mode); } else return 0; } String text = ta.getText(); if (IJ.isWindows() && !IJ.isVista()) text = text.replaceAll("\r\n", "\n"); char[] chars = new char[text.length()]; chars = text.toCharArray(); int count=1; debugStart=0; int len = chars.length; debugEnd = len; for (int i=0; i<len; i++) { if (chars[i]=='\n') count++; if (count==n && debugStart==0) debugStart=i+1; else if (count==n+1) { debugEnd=i; break; } } //IJ.log("debug: "+debugStart+" "+debugEnd+" "+len+" "+count); if (debugStart==1) debugStart = 0; if ((debugStart==0||debugStart==len) && debugEnd==len) return 0; // skip code added with Interpreter.setAdditionalFunctions() ta.select(debugStart, debugEnd); if (debugWindow!=null && !debugWindow.isShowing()) { interp.setEditor(null); debugWindow = null; } else debugWindow = interp.updateDebugWindow(interp.getVariables(), debugWindow); if (mode==Interpreter.STEP) { step = false; while (!step && !interp.done() && isVisible()) IJ.wait(5); } else { if (mode==Interpreter.FAST_TRACE) IJ.wait(5); else IJ.wait(150); } return 0; } public static Editor getInstance() { return instance; } public static String getJSPrefix(String arg) { return JavaScriptIncludes+"function getArgument() {return \""+arg+"\";};"; } /** Changes Mac OS 9 (CR) and Windows (CRLF) line separators to line feeds (LF). */ public void fixLineEndings() { String text = ta.getText(); text = text.replaceAll("\r\n", "\n"); text = text.replaceAll("\r", "\n"); ta.setText(text); } public boolean fileChanged() { return changes; } }