diff agent/src/share/classes/sun/jvm/hotspot/ui/SourceCodePanel.java @ 0:a61af66fc99e jdk7-b24

Initial load
author duke
date Sat, 01 Dec 2007 00:00:00 +0000
parents
children c18cbe5936b8
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/src/share/classes/sun/jvm/hotspot/ui/SourceCodePanel.java	Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,303 @@
+/*
+ * Copyright 2001-2002 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ */
+
+package sun.jvm.hotspot.ui;
+
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.swing.*;
+import javax.swing.text.BadLocationException;
+
+/** Panel supporting loading of and scrolling through source code.
+    Contains convenience routines for implementing the Editor
+    interface. */
+
+public class SourceCodePanel extends JPanel {
+  private JTextArea source;
+  private RowHeader header;
+  private String filename;
+  // Amount of white space between edges, line numbers and icons
+  private static final int LINE_NO_SPACE = 4;
+  // Size of icons in resources directory
+  private static final int ICON_SIZE = 12;
+  // Icons used in panel drawing
+  private static Icon topFrameCurLine;
+  private static Icon lowerFrameCurLine;
+  private static Icon breakpoint;
+  // State
+  private int highlightedLine = -1;
+  private Set/*<Integer>*/ breakpoints = new HashSet(); // Zero-based lines internally
+  // Parent Editor container and EditorCommands object for setting breakpoints
+  private EditorCommands comm;
+  private Editor parent;
+
+  /** Support for displaying icons and line numbers in row header of
+      scroll pane */
+  class RowHeader extends JPanel {
+    private JViewport view;
+    private boolean   showLineNumbers;
+    private int       width;
+    private int       rowHeight;
+    private boolean   initted;
+
+    public RowHeader() {
+      super();
+      initted = true;
+      addHierarchyBoundsListener(new HierarchyBoundsAdapter() {
+          public void ancestorResized(HierarchyEvent e) {
+            recomputeSize();
+          }
+        });
+    }
+
+    public void paint(Graphics g) {
+      super.paint(g);
+      if (getShowLineNumbers()) {
+        // Visible region of header panel, in coordinate system of the
+        // panel, is provided by clip bounds of Graphics object. This
+        // is used to figure out which line numbers to draw.
+        Rectangle clip = g.getClipBounds();
+        // To avoid missing lines, round down starting line number and
+        // round up ending line number
+        int start = clip.y / rowHeight;
+        int end   = start + (clip.height + (rowHeight - 1)) / rowHeight;
+        // Draw these line numbers, right justified to look better
+        FontMetrics fm = getFontMetrics(getFont());
+        int ascent = fm.getMaxAscent(); // Causes proper alignment -- trial-and-error
+        for (int i = start; i <= end; i++) {
+          // Line numbers are 1-based
+          String str = Integer.toString(i + 1);
+          int strWidth = GraphicsUtilities.getStringWidth(str, fm);
+          g.drawString(str, width - strWidth - LINE_NO_SPACE, ascent + rowHeight * i);
+
+          // Draw breakpoint if necessary
+          if (breakpoints.contains(new Integer(i))) {
+            breakpoint.paintIcon(this, g, LINE_NO_SPACE, rowHeight * i);
+          }
+
+          // Draw current line icon if necessary
+          if (i == highlightedLine) {
+            // FIXME: use correct icon (not always topmost frame)
+            topFrameCurLine.paintIcon(this, g, LINE_NO_SPACE, rowHeight * i);
+          }
+        }
+      }
+    }
+
+    public boolean getShowLineNumbers() {
+      return showLineNumbers;
+    }
+
+    public void setShowLineNumbers(boolean val) {
+      if (val != showLineNumbers) {
+        showLineNumbers = val;
+        recomputeSize();
+        // Force re-layout
+        invalidate();
+        validate();
+      }
+    }
+
+    public void setFont(Font f) {
+      super.setFont(f);
+      rowHeight = getFontMetrics(f).getHeight();
+      recomputeSize();
+    }
+
+    void setViewport(JViewport view) {
+      this.view = view;
+    }
+
+    void recomputeSize() {
+      if (!initted) return;
+      if (view == null) return;
+      width = ICON_SIZE + 2 * LINE_NO_SPACE;
+      try {
+        int numLines = 1 + source.getLineOfOffset(source.getDocument().getEndPosition().getOffset() - 1);
+        String str = Integer.toString(numLines);
+        if (getShowLineNumbers()) {
+          // Compute width based on whether we are drawing line numbers
+          width += GraphicsUtilities.getStringWidth(str, getFontMetrics(getFont())) + LINE_NO_SPACE;
+        }
+        // FIXME: add on width for all icons (breakpoint, current line,
+        // current line in caller frame)
+        Dimension d = new Dimension(width, numLines * getFontMetrics(getFont()).getHeight());
+        setSize(d);
+        setPreferredSize(d);
+      } catch (BadLocationException e) {
+        e.printStackTrace();
+      }
+    }
+  }
+
+  public SourceCodePanel() {
+    maybeLoadIcons();
+
+    // Build user interface
+    setLayout(new BorderLayout());
+    source = new JTextArea();
+    source.setEditable(false);
+    source.getCaret().setVisible(true);
+    header = new RowHeader();
+    header.setShowLineNumbers(true);
+    JScrollPane scroller = new JScrollPane(source);
+    JViewport rowView = new JViewport();
+    rowView.setView(header);
+    header.setViewport(rowView);
+    rowView.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
+    scroller.setRowHeader(rowView);
+    add(scroller, BorderLayout.CENTER);
+    // Reset font now that header and source are present
+    setFont(getFont());
+
+    source.addFocusListener(new FocusAdapter() {
+        public void focusGained(FocusEvent e) {
+          source.getCaret().setVisible(true);
+        }
+      });
+
+    source.addKeyListener(new KeyAdapter() {
+        public void keyPressed(KeyEvent e) {
+          if (e.getKeyCode() == KeyEvent.VK_F9) {
+            int lineNo = getCurrentLineNumber();
+            // Only the debugger can figure out whether we are setting
+            // or clearing a breakpoint, since it has the debug
+            // information available and knows whether we're on a
+            // valid line
+            comm.toggleBreakpointAtLine(parent, lineNo);
+          }
+        }
+      });
+
+  }
+
+  public void setFont(Font f) {
+    super.setFont(f);
+    if (source != null) {
+      source.setFont(f);
+    }
+    if (header != null) {
+      header.setFont(f);
+    }
+  }
+
+  public boolean getShowLineNumbers() {
+    return header.getShowLineNumbers();
+  }
+
+  public void setShowLineNumbers(boolean val) {
+    header.setShowLineNumbers(val);
+  }
+
+  public boolean openFile(String filename) {
+    try {
+      this.filename = filename;
+      File file = new File(filename);
+      int len = (int) file.length();
+      StringBuffer buf = new StringBuffer(len); // Approximation
+      char[] tmp = new char[4096];
+      FileReader in = new FileReader(file);
+      int res = 0;
+      do {
+        res = in.read(tmp, 0, tmp.length);
+        if (res >= 0) {
+          buf.append(tmp, 0, res);
+        }
+      } while (res != -1);
+      in.close();
+      String text = buf.toString();
+      source.setText(text);
+      header.recomputeSize();
+      return true;
+    } catch (IOException e) {
+      return false;
+    }
+  }
+
+  public String getSourceFileName() {
+    return filename;
+  }
+
+  /** Line number is one-based */
+  public int getCurrentLineNumber() {
+    try {
+      return 1 + source.getLineOfOffset(source.getCaretPosition());
+    } catch (BadLocationException e) {
+      return 0;
+    }
+  }
+
+  /** Line number is one-based */
+  public void showLineNumber(int lineNo) {
+    try {
+      int offset = source.getLineStartOffset(lineNo - 1);
+      Rectangle rect = source.modelToView(offset);
+      if (rect == null) {
+        return;
+      }
+      source.scrollRectToVisible(rect);
+    } catch (BadLocationException e) {
+      e.printStackTrace();
+    }
+  }
+
+  /** Line number is one-based */
+  public void highlightLineNumber(int lineNo) {
+    highlightedLine = lineNo - 1;
+  }
+
+  public void showBreakpointAtLine(int lineNo)  { breakpoints.add(new Integer(lineNo - 1));    repaint(); }
+  public boolean hasBreakpointAtLine(int lineNo){ return breakpoints.contains(new Integer(lineNo - 1));   }
+  public void clearBreakpointAtLine(int lineNo) { breakpoints.remove(new Integer(lineNo - 1)); repaint(); }
+  public void clearBreakpoints()                { breakpoints.clear();                         repaint(); }
+
+  public void setEditorCommands(EditorCommands comm, Editor parent) {
+    this.comm = comm;
+    this.parent = parent;
+  }
+
+  public void requestFocus() {
+    source.requestFocus();
+  }
+
+  //----------------------------------------------------------------------
+  // Internals only below this point
+  //
+
+  private void maybeLoadIcons() {
+    if (topFrameCurLine == null) {
+      topFrameCurLine   = loadIcon("resources/arrow.png");
+      lowerFrameCurLine = loadIcon("resources/triangle.png");
+      breakpoint        = loadIcon("resources/breakpoint.png");
+    }
+  }
+
+  private Icon loadIcon(String which) {
+    URL url = getClass().getResource(which);
+    return new ImageIcon(url);
+  }
+}