// // CodeEditor.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad.util; import java.awt.*; import javax.swing.*; import javax.swing.event.*; import javax.swing.undo.*; import visad.VisADException; /** An editor for writing and executing source code in Java runtime. */ public abstract class CodeEditor extends TextEditor { /** text pane containing line numbers */ protected JTextArea lineNumbers; /** number of lines of code in the document */ protected int numLines; /** number of digits in lines of code in the document */ protected int numDigits; /** constructs a CodeEditor */ public CodeEditor() { this(null); } /** constructs a CodeEditor containing text from the given filename */ public CodeEditor(String filename) { super(filename); // set up line numbers final int fontWidth = getFontMetrics(MONO).stringWidth(" "); lineNumbers = new JTextArea("1") { public Dimension getPreferredSize() { Dimension d = super.getPreferredSize(); d.width = numDigits * fontWidth; return d; } }; lineNumbers.setEditable(false); lineNumbers.setFont(MONO); numLines = 1; numDigits = 1; JPanel p = new JPanel() { public void paint(Graphics g) { // paint a thin gray line down right-hand side of line numbering super.paint(g); Dimension d = getSize(); int w = d.width - 5; int h = d.height - 1; g.setColor(Color.gray); g.drawLine(w, 0, w, h); } public Dimension getPreferredSize() { Dimension d = lineNumbers.getPreferredSize(); d.width += 10; return d; } }; p.setBackground(Color.white); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); p.add(lineNumbers); setRowHeaderView(p); } /** highlights the given line of code in the document */ public void highlightLine(int line) { int start = 0; String s = text.getText() + "\n"; for (int i=0; i<line-1; i++) start = s.indexOf("\n", start) + 1; int end = s.indexOf("\n", start); text.requestFocus(); text.setCaretPosition(start); text.moveCaretPosition(end); } /** executes the source code in Java runtime */ public abstract void run() throws VisADException; /** compiles the source code to a Java class */ public abstract void compile() throws VisADException; /** executes the given line of code immediately in Java runtime */ public abstract void exec(String line) throws VisADException; /** updates line numbers to match document text */ protected void updateLineNumbers() { String s = text.getText(); int len = s.length(); int count = 1; // count number of lines in document int index = s.indexOf("\n"); while (index >= 0) { count++; index = s.indexOf("\n", index + 1); } if (count == numLines) return; // compute index into line numbers text string String l = lineNumbers.getText() + "\n"; int digits = ("" + count).length(); int spot = 0; int nine = 9; for (int i=2; i<=digits; i++) { spot += i * nine; nine *= 10; } int ten = nine / 9; spot += (digits + 1) * (count - ten + 1); // update line numbers text string int maxSpot = l.length(); String newL; if (spot < maxSpot) { // eliminate extra line numbers newL = l.substring(0, spot - 1); } else { // append additional line numbers StringBuffer sb = new StringBuffer(spot); sb.append(l); for (int i=numLines+1; i<count; i++) { sb.append(i); sb.append("\n"); } sb.append(count); newL = sb.toString(); } numLines = count; numDigits = digits; lineNumbers.setText(newL); } /** undoes the last edit */ public void undo() throws CannotUndoException { super.undo(); updateLineNumbers(); } /** redoes the last undone edit */ public void redo() throws CannotRedoException { super.redo(); updateLineNumbers(); } /** updates line numbers when undoable action occurs */ public void undoableEditHappened(UndoableEditEvent e) { super.undoableEditHappened(e); if (!e.getEdit().isSignificant()) return; updateLineNumbers(); } }