1*b1cdbd2cSJim Jagielski /************************************************************** 2*b1cdbd2cSJim Jagielski * 3*b1cdbd2cSJim Jagielski * Licensed to the Apache Software Foundation (ASF) under one 4*b1cdbd2cSJim Jagielski * or more contributor license agreements. See the NOTICE file 5*b1cdbd2cSJim Jagielski * distributed with this work for additional information 6*b1cdbd2cSJim Jagielski * regarding copyright ownership. The ASF licenses this file 7*b1cdbd2cSJim Jagielski * to you under the Apache License, Version 2.0 (the 8*b1cdbd2cSJim Jagielski * "License"); you may not use this file except in compliance 9*b1cdbd2cSJim Jagielski * with the License. You may obtain a copy of the License at 10*b1cdbd2cSJim Jagielski * 11*b1cdbd2cSJim Jagielski * http://www.apache.org/licenses/LICENSE-2.0 12*b1cdbd2cSJim Jagielski * 13*b1cdbd2cSJim Jagielski * Unless required by applicable law or agreed to in writing, 14*b1cdbd2cSJim Jagielski * software distributed under the License is distributed on an 15*b1cdbd2cSJim Jagielski * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*b1cdbd2cSJim Jagielski * KIND, either express or implied. See the License for the 17*b1cdbd2cSJim Jagielski * specific language governing permissions and limitations 18*b1cdbd2cSJim Jagielski * under the License. 19*b1cdbd2cSJim Jagielski * 20*b1cdbd2cSJim Jagielski *************************************************************/ 21*b1cdbd2cSJim Jagielski 22*b1cdbd2cSJim Jagielski import javax.swing.JFrame; 23*b1cdbd2cSJim Jagielski import javax.swing.JTextArea; 24*b1cdbd2cSJim Jagielski import javax.swing.JPanel; 25*b1cdbd2cSJim Jagielski import javax.swing.JScrollPane; 26*b1cdbd2cSJim Jagielski import javax.swing.JButton; 27*b1cdbd2cSJim Jagielski import javax.swing.JComponent; 28*b1cdbd2cSJim Jagielski import javax.swing.JFileChooser; 29*b1cdbd2cSJim Jagielski import javax.swing.JOptionPane; 30*b1cdbd2cSJim Jagielski import javax.swing.text.Document; 31*b1cdbd2cSJim Jagielski import javax.swing.event.DocumentListener; 32*b1cdbd2cSJim Jagielski import javax.swing.event.DocumentEvent; 33*b1cdbd2cSJim Jagielski 34*b1cdbd2cSJim Jagielski import java.awt.FlowLayout; 35*b1cdbd2cSJim Jagielski import java.awt.Graphics; 36*b1cdbd2cSJim Jagielski import java.awt.Color; 37*b1cdbd2cSJim Jagielski import java.awt.Font; 38*b1cdbd2cSJim Jagielski import java.awt.FontMetrics; 39*b1cdbd2cSJim Jagielski import java.awt.Polygon; 40*b1cdbd2cSJim Jagielski import java.awt.Rectangle; 41*b1cdbd2cSJim Jagielski import java.awt.Dimension; 42*b1cdbd2cSJim Jagielski import java.awt.event.ActionListener; 43*b1cdbd2cSJim Jagielski import java.awt.event.ActionEvent; 44*b1cdbd2cSJim Jagielski 45*b1cdbd2cSJim Jagielski import java.io.File; 46*b1cdbd2cSJim Jagielski import java.io.InputStream; 47*b1cdbd2cSJim Jagielski import java.io.FileInputStream; 48*b1cdbd2cSJim Jagielski import java.io.FileOutputStream; 49*b1cdbd2cSJim Jagielski import java.io.IOException; 50*b1cdbd2cSJim Jagielski 51*b1cdbd2cSJim Jagielski import drafts.com.sun.star.script.framework.runtime.XScriptContext; 52*b1cdbd2cSJim Jagielski import bsh.Interpreter; 53*b1cdbd2cSJim Jagielski 54*b1cdbd2cSJim Jagielski public class OOBeanShellDebugger implements OOScriptDebugger, ActionListener, DocumentListener { 55*b1cdbd2cSJim Jagielski 56*b1cdbd2cSJim Jagielski private JFrame frame; 57*b1cdbd2cSJim Jagielski private JTextArea ta; 58*b1cdbd2cSJim Jagielski private GlyphGutter gg; 59*b1cdbd2cSJim Jagielski private XScriptContext context; 60*b1cdbd2cSJim Jagielski private int currentPosition = -1; 61*b1cdbd2cSJim Jagielski private int linecount; 62*b1cdbd2cSJim Jagielski private Interpreter sessionInterpreter; 63*b1cdbd2cSJim Jagielski private Thread execThread = null; 64*b1cdbd2cSJim Jagielski private String filename = null; 65*b1cdbd2cSJim Jagielski 66*b1cdbd2cSJim Jagielski /* Entry point for script execution */ go(XScriptContext context, String filename)67*b1cdbd2cSJim Jagielski public void go(XScriptContext context, String filename) { 68*b1cdbd2cSJim Jagielski if (filename != null && filename != "") { 69*b1cdbd2cSJim Jagielski try { 70*b1cdbd2cSJim Jagielski FileInputStream fis = new FileInputStream(filename); 71*b1cdbd2cSJim Jagielski this.filename = filename; 72*b1cdbd2cSJim Jagielski go(context, fis); 73*b1cdbd2cSJim Jagielski } 74*b1cdbd2cSJim Jagielski catch (IOException ioe) { 75*b1cdbd2cSJim Jagielski JOptionPane.showMessageDialog(frame, 76*b1cdbd2cSJim Jagielski "Error loading file: " + ioe.getMessage(), 77*b1cdbd2cSJim Jagielski "Error", JOptionPane.ERROR_MESSAGE); 78*b1cdbd2cSJim Jagielski } 79*b1cdbd2cSJim Jagielski } 80*b1cdbd2cSJim Jagielski } 81*b1cdbd2cSJim Jagielski 82*b1cdbd2cSJim Jagielski /* Entry point for script execution */ go(XScriptContext context, InputStream in)83*b1cdbd2cSJim Jagielski public void go(XScriptContext context, InputStream in) { 84*b1cdbd2cSJim Jagielski this.context = context; 85*b1cdbd2cSJim Jagielski initUI(); 86*b1cdbd2cSJim Jagielski 87*b1cdbd2cSJim Jagielski if (in != null) { 88*b1cdbd2cSJim Jagielski try { 89*b1cdbd2cSJim Jagielski loadFile(in); 90*b1cdbd2cSJim Jagielski } 91*b1cdbd2cSJim Jagielski catch (IOException ioe) { 92*b1cdbd2cSJim Jagielski JOptionPane.showMessageDialog(frame, 93*b1cdbd2cSJim Jagielski "Error loading stream: " + ioe.getMessage(), 94*b1cdbd2cSJim Jagielski "Error", JOptionPane.ERROR_MESSAGE); 95*b1cdbd2cSJim Jagielski } 96*b1cdbd2cSJim Jagielski } 97*b1cdbd2cSJim Jagielski } 98*b1cdbd2cSJim Jagielski loadFile(InputStream in)99*b1cdbd2cSJim Jagielski public void loadFile(InputStream in) throws IOException { 100*b1cdbd2cSJim Jagielski 101*b1cdbd2cSJim Jagielski /* Remove ourselves as a DocumentListener while loading the file 102*b1cdbd2cSJim Jagielski so we don't get a storm of DocumentEvents during loading */ 103*b1cdbd2cSJim Jagielski ta.getDocument().removeDocumentListener(this); 104*b1cdbd2cSJim Jagielski 105*b1cdbd2cSJim Jagielski byte[] contents = new byte[1024]; 106*b1cdbd2cSJim Jagielski int len = 0, pos = 0; 107*b1cdbd2cSJim Jagielski 108*b1cdbd2cSJim Jagielski while ((len = in.read(contents, 0, 1024)) != -1) { 109*b1cdbd2cSJim Jagielski ta.insert(new String(contents, 0, len), pos); 110*b1cdbd2cSJim Jagielski pos += len; 111*b1cdbd2cSJim Jagielski } 112*b1cdbd2cSJim Jagielski 113*b1cdbd2cSJim Jagielski try { 114*b1cdbd2cSJim Jagielski in.close(); 115*b1cdbd2cSJim Jagielski } 116*b1cdbd2cSJim Jagielski catch (IOException ignore) { 117*b1cdbd2cSJim Jagielski } 118*b1cdbd2cSJim Jagielski 119*b1cdbd2cSJim Jagielski /* Update the GlyphGutter and add back the DocumentListener */ 120*b1cdbd2cSJim Jagielski gg.update(); 121*b1cdbd2cSJim Jagielski ta.getDocument().addDocumentListener(this); 122*b1cdbd2cSJim Jagielski } 123*b1cdbd2cSJim Jagielski initUI()124*b1cdbd2cSJim Jagielski private void initUI() { 125*b1cdbd2cSJim Jagielski frame = new JFrame("BeanShell Debug Window"); 126*b1cdbd2cSJim Jagielski ta = new JTextArea(); 127*b1cdbd2cSJim Jagielski ta.setRows(15); 128*b1cdbd2cSJim Jagielski ta.setColumns(40); 129*b1cdbd2cSJim Jagielski ta.setLineWrap(false); 130*b1cdbd2cSJim Jagielski linecount = ta.getLineCount(); 131*b1cdbd2cSJim Jagielski 132*b1cdbd2cSJim Jagielski gg = new GlyphGutter(this); 133*b1cdbd2cSJim Jagielski 134*b1cdbd2cSJim Jagielski final JScrollPane sp = new JScrollPane(); 135*b1cdbd2cSJim Jagielski sp.setViewportView(ta); 136*b1cdbd2cSJim Jagielski sp.setRowHeaderView(gg); 137*b1cdbd2cSJim Jagielski 138*b1cdbd2cSJim Jagielski ta.getDocument().addDocumentListener(this); 139*b1cdbd2cSJim Jagielski String[] labels = {"Run", "Clear", "Save", "Close"}; 140*b1cdbd2cSJim Jagielski JPanel p = new JPanel(); 141*b1cdbd2cSJim Jagielski p.setLayout(new FlowLayout()); 142*b1cdbd2cSJim Jagielski 143*b1cdbd2cSJim Jagielski for (int i = 0; i < labels.length; i++) { 144*b1cdbd2cSJim Jagielski JButton b = new JButton(labels[i]); 145*b1cdbd2cSJim Jagielski b.addActionListener(this); 146*b1cdbd2cSJim Jagielski p.add(b); 147*b1cdbd2cSJim Jagielski 148*b1cdbd2cSJim Jagielski if (labels[i].equals("Save") && filename == null) { 149*b1cdbd2cSJim Jagielski b.setEnabled(false); 150*b1cdbd2cSJim Jagielski } 151*b1cdbd2cSJim Jagielski } 152*b1cdbd2cSJim Jagielski 153*b1cdbd2cSJim Jagielski frame.getContentPane().add(sp, "Center"); 154*b1cdbd2cSJim Jagielski frame.getContentPane().add(p, "South"); 155*b1cdbd2cSJim Jagielski frame.pack(); 156*b1cdbd2cSJim Jagielski frame.show(); 157*b1cdbd2cSJim Jagielski } 158*b1cdbd2cSJim Jagielski 159*b1cdbd2cSJim Jagielski /* Implementation of DocumentListener interface */ insertUpdate(DocumentEvent e)160*b1cdbd2cSJim Jagielski public void insertUpdate(DocumentEvent e) { 161*b1cdbd2cSJim Jagielski doChanged(e); 162*b1cdbd2cSJim Jagielski } 163*b1cdbd2cSJim Jagielski removeUpdate(DocumentEvent e)164*b1cdbd2cSJim Jagielski public void removeUpdate(DocumentEvent e) { 165*b1cdbd2cSJim Jagielski doChanged(e); 166*b1cdbd2cSJim Jagielski } 167*b1cdbd2cSJim Jagielski changedUpdate(DocumentEvent e)168*b1cdbd2cSJim Jagielski public void changedUpdate(DocumentEvent e) { 169*b1cdbd2cSJim Jagielski doChanged(e); 170*b1cdbd2cSJim Jagielski } 171*b1cdbd2cSJim Jagielski 172*b1cdbd2cSJim Jagielski /* If the number of lines in the JTextArea has changed then update the 173*b1cdbd2cSJim Jagielski GlyphGutter */ doChanged(DocumentEvent e)174*b1cdbd2cSJim Jagielski public void doChanged(DocumentEvent e) { 175*b1cdbd2cSJim Jagielski if (linecount != ta.getLineCount()) { 176*b1cdbd2cSJim Jagielski gg.update(); 177*b1cdbd2cSJim Jagielski linecount = ta.getLineCount(); 178*b1cdbd2cSJim Jagielski } 179*b1cdbd2cSJim Jagielski } 180*b1cdbd2cSJim Jagielski startExecution()181*b1cdbd2cSJim Jagielski private void startExecution() { 182*b1cdbd2cSJim Jagielski execThread = new Thread() { 183*b1cdbd2cSJim Jagielski public void run() { 184*b1cdbd2cSJim Jagielski Interpreter interpreter = new Interpreter(); 185*b1cdbd2cSJim Jagielski interpreter.getNameSpace().clear(); 186*b1cdbd2cSJim Jagielski 187*b1cdbd2cSJim Jagielski // reset position and repaint gutter so no red arrow appears 188*b1cdbd2cSJim Jagielski currentPosition = -1; 189*b1cdbd2cSJim Jagielski gg.repaint(); 190*b1cdbd2cSJim Jagielski 191*b1cdbd2cSJim Jagielski try { 192*b1cdbd2cSJim Jagielski interpreter.set("context", context); 193*b1cdbd2cSJim Jagielski interpreter.eval(ta.getText()); 194*b1cdbd2cSJim Jagielski } 195*b1cdbd2cSJim Jagielski catch (bsh.EvalError err) { 196*b1cdbd2cSJim Jagielski currentPosition = err.getErrorLineNumber() - 1; 197*b1cdbd2cSJim Jagielski try { 198*b1cdbd2cSJim Jagielski // scroll to line of the error 199*b1cdbd2cSJim Jagielski int line = ta.getLineStartOffset(currentPosition); 200*b1cdbd2cSJim Jagielski Rectangle rect = ta.modelToView(line); 201*b1cdbd2cSJim Jagielski ta.scrollRectToVisible(rect); 202*b1cdbd2cSJim Jagielski } 203*b1cdbd2cSJim Jagielski catch (Exception e) { 204*b1cdbd2cSJim Jagielski // couldn't scroll to line, do nothing 205*b1cdbd2cSJim Jagielski } 206*b1cdbd2cSJim Jagielski gg.repaint(); 207*b1cdbd2cSJim Jagielski 208*b1cdbd2cSJim Jagielski JOptionPane.showMessageDialog(frame, "Error at line " + 209*b1cdbd2cSJim Jagielski String.valueOf(err.getErrorLineNumber()) + 210*b1cdbd2cSJim Jagielski "\n\n: " + err.getErrorText(), 211*b1cdbd2cSJim Jagielski "Error", JOptionPane.ERROR_MESSAGE); 212*b1cdbd2cSJim Jagielski } 213*b1cdbd2cSJim Jagielski catch (Exception e) { 214*b1cdbd2cSJim Jagielski JOptionPane.showMessageDialog(frame, 215*b1cdbd2cSJim Jagielski "Error: " + e.getMessage(), 216*b1cdbd2cSJim Jagielski "Error", JOptionPane.ERROR_MESSAGE); 217*b1cdbd2cSJim Jagielski } 218*b1cdbd2cSJim Jagielski } 219*b1cdbd2cSJim Jagielski }; 220*b1cdbd2cSJim Jagielski execThread.start(); 221*b1cdbd2cSJim Jagielski } 222*b1cdbd2cSJim Jagielski promptForSaveName()223*b1cdbd2cSJim Jagielski private void promptForSaveName() { 224*b1cdbd2cSJim Jagielski JFileChooser chooser = new JFileChooser(); 225*b1cdbd2cSJim Jagielski chooser.setFileFilter(new javax.swing.filechooser.FileFilter() { 226*b1cdbd2cSJim Jagielski public boolean accept(File f) { 227*b1cdbd2cSJim Jagielski if (f.isDirectory() || f.getName().endsWith(".bsh")) { 228*b1cdbd2cSJim Jagielski return true; 229*b1cdbd2cSJim Jagielski } 230*b1cdbd2cSJim Jagielski return false; 231*b1cdbd2cSJim Jagielski } 232*b1cdbd2cSJim Jagielski 233*b1cdbd2cSJim Jagielski public String getDescription() { 234*b1cdbd2cSJim Jagielski return ("BeanShell files: *.bsh"); 235*b1cdbd2cSJim Jagielski } 236*b1cdbd2cSJim Jagielski }); 237*b1cdbd2cSJim Jagielski 238*b1cdbd2cSJim Jagielski int ret = chooser.showSaveDialog(frame); 239*b1cdbd2cSJim Jagielski 240*b1cdbd2cSJim Jagielski if (ret == JFileChooser.APPROVE_OPTION) { 241*b1cdbd2cSJim Jagielski filename = chooser.getSelectedFile().getAbsolutePath(); 242*b1cdbd2cSJim Jagielski if (!filename.endsWith(".bsh")) { 243*b1cdbd2cSJim Jagielski filename += ".bsh"; 244*b1cdbd2cSJim Jagielski } 245*b1cdbd2cSJim Jagielski } 246*b1cdbd2cSJim Jagielski 247*b1cdbd2cSJim Jagielski } 248*b1cdbd2cSJim Jagielski saveTextArea()249*b1cdbd2cSJim Jagielski private void saveTextArea() { 250*b1cdbd2cSJim Jagielski if (filename == null) { 251*b1cdbd2cSJim Jagielski promptForSaveName(); 252*b1cdbd2cSJim Jagielski } 253*b1cdbd2cSJim Jagielski 254*b1cdbd2cSJim Jagielski FileOutputStream fos = null; 255*b1cdbd2cSJim Jagielski if (filename != null) { 256*b1cdbd2cSJim Jagielski try { 257*b1cdbd2cSJim Jagielski File f = new File(filename); 258*b1cdbd2cSJim Jagielski fos = new FileOutputStream(f); 259*b1cdbd2cSJim Jagielski String s = ta.getText(); 260*b1cdbd2cSJim Jagielski fos.write(s.getBytes(), 0, s.length()); 261*b1cdbd2cSJim Jagielski } 262*b1cdbd2cSJim Jagielski catch (IOException ioe) { 263*b1cdbd2cSJim Jagielski JOptionPane.showMessageDialog(frame, 264*b1cdbd2cSJim Jagielski "Error saving file: " + ioe.getMessage(), 265*b1cdbd2cSJim Jagielski "Error", JOptionPane.ERROR_MESSAGE); 266*b1cdbd2cSJim Jagielski } 267*b1cdbd2cSJim Jagielski finally { 268*b1cdbd2cSJim Jagielski if (fos != null) { 269*b1cdbd2cSJim Jagielski try { 270*b1cdbd2cSJim Jagielski fos.close(); 271*b1cdbd2cSJim Jagielski } 272*b1cdbd2cSJim Jagielski catch (IOException ignore) { 273*b1cdbd2cSJim Jagielski } 274*b1cdbd2cSJim Jagielski } 275*b1cdbd2cSJim Jagielski } 276*b1cdbd2cSJim Jagielski } 277*b1cdbd2cSJim Jagielski } 278*b1cdbd2cSJim Jagielski actionPerformed(ActionEvent e)279*b1cdbd2cSJim Jagielski public void actionPerformed(ActionEvent e) { 280*b1cdbd2cSJim Jagielski if (e.getActionCommand().equals("Run")) { 281*b1cdbd2cSJim Jagielski startExecution(); 282*b1cdbd2cSJim Jagielski } 283*b1cdbd2cSJim Jagielski else if (e.getActionCommand().equals("Close")) { 284*b1cdbd2cSJim Jagielski frame.dispose(); 285*b1cdbd2cSJim Jagielski } 286*b1cdbd2cSJim Jagielski else if (e.getActionCommand().equals("Save")) { 287*b1cdbd2cSJim Jagielski saveTextArea(); 288*b1cdbd2cSJim Jagielski } 289*b1cdbd2cSJim Jagielski else if (e.getActionCommand().equals("Clear")) { 290*b1cdbd2cSJim Jagielski ta.setText(""); 291*b1cdbd2cSJim Jagielski } 292*b1cdbd2cSJim Jagielski } 293*b1cdbd2cSJim Jagielski getTextArea()294*b1cdbd2cSJim Jagielski public JTextArea getTextArea() { 295*b1cdbd2cSJim Jagielski return ta; 296*b1cdbd2cSJim Jagielski } 297*b1cdbd2cSJim Jagielski getCurrentPosition()298*b1cdbd2cSJim Jagielski public int getCurrentPosition() { 299*b1cdbd2cSJim Jagielski return currentPosition; 300*b1cdbd2cSJim Jagielski } 301*b1cdbd2cSJim Jagielski } 302*b1cdbd2cSJim Jagielski 303*b1cdbd2cSJim Jagielski class GlyphGutter extends JComponent { 304*b1cdbd2cSJim Jagielski 305*b1cdbd2cSJim Jagielski private OOBeanShellDebugger debugger; 306*b1cdbd2cSJim Jagielski private final String DUMMY_STRING = "99"; 307*b1cdbd2cSJim Jagielski GlyphGutter(OOBeanShellDebugger debugger)308*b1cdbd2cSJim Jagielski GlyphGutter(OOBeanShellDebugger debugger) { 309*b1cdbd2cSJim Jagielski this.debugger = debugger; 310*b1cdbd2cSJim Jagielski update(); 311*b1cdbd2cSJim Jagielski } 312*b1cdbd2cSJim Jagielski update()313*b1cdbd2cSJim Jagielski public void update() { 314*b1cdbd2cSJim Jagielski JTextArea textArea = debugger.getTextArea(); 315*b1cdbd2cSJim Jagielski Font font = textArea.getFont(); 316*b1cdbd2cSJim Jagielski setFont(font); 317*b1cdbd2cSJim Jagielski 318*b1cdbd2cSJim Jagielski FontMetrics metrics = getFontMetrics(font); 319*b1cdbd2cSJim Jagielski int h = metrics.getHeight(); 320*b1cdbd2cSJim Jagielski int lineCount = textArea.getLineCount() + 1; 321*b1cdbd2cSJim Jagielski 322*b1cdbd2cSJim Jagielski String dummy = Integer.toString(lineCount); 323*b1cdbd2cSJim Jagielski if (dummy.length() < 2) { 324*b1cdbd2cSJim Jagielski dummy = DUMMY_STRING; 325*b1cdbd2cSJim Jagielski } 326*b1cdbd2cSJim Jagielski 327*b1cdbd2cSJim Jagielski Dimension d = new Dimension(); 328*b1cdbd2cSJim Jagielski d.width = metrics.stringWidth(dummy) + 16; 329*b1cdbd2cSJim Jagielski d.height = lineCount * h + 100; 330*b1cdbd2cSJim Jagielski setPreferredSize(d); 331*b1cdbd2cSJim Jagielski setSize(d); 332*b1cdbd2cSJim Jagielski } 333*b1cdbd2cSJim Jagielski paintComponent(Graphics g)334*b1cdbd2cSJim Jagielski public void paintComponent(Graphics g) { 335*b1cdbd2cSJim Jagielski JTextArea textArea = debugger.getTextArea(); 336*b1cdbd2cSJim Jagielski 337*b1cdbd2cSJim Jagielski Font font = textArea.getFont(); 338*b1cdbd2cSJim Jagielski g.setFont(font); 339*b1cdbd2cSJim Jagielski 340*b1cdbd2cSJim Jagielski FontMetrics metrics = getFontMetrics(font); 341*b1cdbd2cSJim Jagielski Rectangle clip = g.getClipBounds(); 342*b1cdbd2cSJim Jagielski 343*b1cdbd2cSJim Jagielski g.setColor(getBackground()); 344*b1cdbd2cSJim Jagielski g.fillRect(clip.x, clip.y, clip.width, clip.height); 345*b1cdbd2cSJim Jagielski 346*b1cdbd2cSJim Jagielski int ascent = metrics.getMaxAscent(); 347*b1cdbd2cSJim Jagielski int h = metrics.getHeight(); 348*b1cdbd2cSJim Jagielski int lineCount = textArea.getLineCount() + 1; 349*b1cdbd2cSJim Jagielski 350*b1cdbd2cSJim Jagielski int startLine = clip.y / h; 351*b1cdbd2cSJim Jagielski int endLine = (clip.y + clip.height) / h + 1; 352*b1cdbd2cSJim Jagielski int width = getWidth(); 353*b1cdbd2cSJim Jagielski if (endLine > lineCount) { 354*b1cdbd2cSJim Jagielski endLine = lineCount; 355*b1cdbd2cSJim Jagielski } 356*b1cdbd2cSJim Jagielski 357*b1cdbd2cSJim Jagielski for (int i = startLine; i < endLine; i++) { 358*b1cdbd2cSJim Jagielski String text; 359*b1cdbd2cSJim Jagielski text = Integer.toString(i + 1) + " "; 360*b1cdbd2cSJim Jagielski int w = metrics.stringWidth(text); 361*b1cdbd2cSJim Jagielski int y = i * h; 362*b1cdbd2cSJim Jagielski g.setColor(Color.blue); 363*b1cdbd2cSJim Jagielski g.drawString(text, 0, y + ascent); 364*b1cdbd2cSJim Jagielski int x = width - ascent; 365*b1cdbd2cSJim Jagielski 366*b1cdbd2cSJim Jagielski // if currentPosition is not -1 then a red arrow will be drawn 367*b1cdbd2cSJim Jagielski if (i == debugger.getCurrentPosition()) { 368*b1cdbd2cSJim Jagielski drawArrow(g, ascent, x, y); 369*b1cdbd2cSJim Jagielski } 370*b1cdbd2cSJim Jagielski } 371*b1cdbd2cSJim Jagielski } 372*b1cdbd2cSJim Jagielski drawArrow(Graphics g, int ascent, int x, int y)373*b1cdbd2cSJim Jagielski private void drawArrow(Graphics g, int ascent, int x, int y) { 374*b1cdbd2cSJim Jagielski Polygon arrow = new Polygon(); 375*b1cdbd2cSJim Jagielski int dx = x; 376*b1cdbd2cSJim Jagielski y += ascent - 10; 377*b1cdbd2cSJim Jagielski int dy = y; 378*b1cdbd2cSJim Jagielski arrow.addPoint(dx, dy + 3); 379*b1cdbd2cSJim Jagielski arrow.addPoint(dx + 5, dy + 3); 380*b1cdbd2cSJim Jagielski for (x = dx + 5; x <= dx + 10; x++, y++) { 381*b1cdbd2cSJim Jagielski arrow.addPoint(x, y); 382*b1cdbd2cSJim Jagielski } 383*b1cdbd2cSJim Jagielski for (x = dx + 9; x >= dx + 5; x--, y++) { 384*b1cdbd2cSJim Jagielski arrow.addPoint(x, y); 385*b1cdbd2cSJim Jagielski } 386*b1cdbd2cSJim Jagielski arrow.addPoint(dx + 5, dy + 7); 387*b1cdbd2cSJim Jagielski arrow.addPoint(dx, dy + 7); 388*b1cdbd2cSJim Jagielski 389*b1cdbd2cSJim Jagielski g.setColor(Color.red); 390*b1cdbd2cSJim Jagielski g.fillPolygon(arrow); 391*b1cdbd2cSJim Jagielski g.setColor(Color.black); 392*b1cdbd2cSJim Jagielski g.drawPolygon(arrow); 393*b1cdbd2cSJim Jagielski } 394*b1cdbd2cSJim Jagielski }; 395*b1cdbd2cSJim Jagielski 396