package app.navigps.gui.VerboseTextPane; /** * Created on 2009-01-13, 21:45:14 * @author vara */ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.*; /** * * @author wara */ public class LineNumber extends JComponent{ /** * */ public final static String CHANGE_VISIBLE_LINE_NUMBER = "linenumber.visibleline"; private float limitColorFontAlpha = 0.8f; private float colorFontAlpha = getLimitColorFontAlpha(); private final static Color DEFAULT_BACKGROUND = new Color(204, 204, 255); private final static Color DEFAULT_FOREGROUND = new Color(0,0,0); private final static Font DEFAULT_FONT = new Font("monospaced", Font.PLAIN, 12); // LineNumber height (abends when I use MAX_VALUE) private final static int DEFAULT_HEIGHT = Integer.MAX_VALUE - 1000000; private final static int DEFAULT_WIDTH = 99; // Set right/left margin private final static int DEFAULT_MARGIN = 5; // Variables for this LineNumber component private FontMetrics fontMetrics; private int lineHeight; private int currentDigits; // Metrics of the component used in the constructor private JComponent component; private int componentFontHeight; private int componentFontAscent; private boolean showNumber = true; private ShowLineNumberAction showNum = new ShowLineNumberAction(); /** * * @param component */ public LineNumber(JComponent component){ if (component == null){ setFont(DEFAULT_FONT); this.component = this; } else{ setFont(component.getFont()); this.component = component; } setBackground(DEFAULT_BACKGROUND); setForeground(DEFAULT_FOREGROUND); setPreferredWidth(DEFAULT_WIDTH); //addMouseListener(new MyMouseListener()); } /** * Calculate the width needed to display the maximum line number * * @param lines */ public void setPreferredWidth(int lines) { int digits = String.valueOf(lines).length(); // Update sizes when number of digits in the line number changes if (digits != currentDigits && digits > 1){ currentDigits = digits; int width = fontMetrics.charWidth('0') * digits; Dimension d = getPreferredSize(); d.setSize(2 * DEFAULT_MARGIN + width, DEFAULT_HEIGHT); setPreferredSize(d); setSize(d); } } /** * Reset variables that are dependent on the font. */ @Override public void setFont(Font font){ super.setFont(font); fontMetrics = getFontMetrics(getFont()); componentFontHeight = fontMetrics.getHeight(); componentFontAscent = fontMetrics.getAscent(); } /** * The line height defaults to the line height of the font for this * component. * * @return */ public int getLineHeight(){ if (lineHeight == 0) return componentFontHeight; else return lineHeight; } /** * Override the default line height with a positive value. * For example, when you want line numbers for a JTable you could * use the JTable row height. * * @param lineHeight */ public void setLineHeight(int lineHeight){ if (lineHeight > 0) this.lineHeight = lineHeight; } /** * * @return */ public int getStartOffset(){ return component.getInsets().top + componentFontAscent; } @Override public void paintComponent(Graphics g){ Graphics2D g2 = (Graphics2D)g; int localLineHeight = getLineHeight(); int startOffset = getStartOffset(); Rectangle drawHere = g.getClipBounds(); //Console.err.println("localLineHeight "+localLineHeight); // Paint the background g2.setColor( getBackground() ); g2.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height); // Determine the number of lines to draw in the foreground. //System.out.println("paintComponent isShow number "+isShowNumber()); if(isShowNumber()){ g2.setColor(getForeground()); AlphaComposite newComposite = AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,getColorFontAlpha()); g2.setComposite(newComposite); int startLineNumber = (drawHere.y / localLineHeight) + 1; int endLineNumber = startLineNumber + (drawHere.height / localLineHeight); int start = (drawHere.y / localLineHeight) * localLineHeight + startOffset; for (int i = startLineNumber; i <= endLineNumber; i++){ String lineNumber = String.valueOf(i); int stringWidth = fontMetrics.stringWidth(lineNumber); int rowWidth = getSize().width; g2.drawString(lineNumber, rowWidth - stringWidth - DEFAULT_MARGIN, start); start += localLineHeight; } int rows = component.getSize().height / componentFontHeight; setPreferredWidth(rows); //System.out.println(""+rows); } } /** * * @param alpha */ public void setColorFontAlpha(float alpha){ colorFontAlpha = alpha<0.0f ? 0.0f : (alpha>1.0f ? 1.0f:getLimitColorFontAlpha()); //System.out.println("ColorAlpha "+colorFontAlpha); } /** * @return the showNumber */ public boolean isShowNumber() { return showNumber; } /** * @param showNumber the showNumber to set */ public void setShowNumber(boolean showNumber) { boolean oldV = this.showNumber; this.showNumber = showNumber; firePropertyChange(LineNumber.CHANGE_VISIBLE_LINE_NUMBER, oldV, showNumber); } /** * @return the limitColorFontAlpha */ public float getLimitColorFontAlpha() { return limitColorFontAlpha; } /** * @param limitColorFontAlpha the limitColorFontAlpha to set */ public void setLimitColorFontAlpha(float limitColorFontAlpha) { this.limitColorFontAlpha = limitColorFontAlpha; } /** * @return the colorFontAlpha */ public float getColorFontAlpha() { return colorFontAlpha; } class ShowLineNumberAction extends AbstractAction{ @Override public void actionPerformed(ActionEvent e) { final float startAlpha = isShowNumber() ? 1.0f : 0.0f; final float andAlpha = !isShowNumber() ? 1.0f : 0.0f; final float incUnit = isShowNumber() ? -0.01f : 0.01f; new Thread(new Runnable() { @Override public void run() { boolean disableShowNumber = false; if(!isShowNumber()) setShowNumber(true); else disableShowNumber = true; for (float i = startAlpha; i < andAlpha+incUnit; i+=incUnit) { setColorFontAlpha(i); LineNumber.this.repaint(); try {Thread.sleep(50);} catch (InterruptedException e) {} } setShowNumber(!disableShowNumber); } }); setShowNumber(!isShowNumber()); repaint(); } } class MyMouseListener implements MouseListener{ @Override public void mouseClicked(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { showNum.actionPerformed(null); } @Override public void mouseReleased(MouseEvent e) { } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } } /** * * @param args */ public static void main(String[] args){ JFrame frame = new JFrame("LineNumberDemo"); frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); JPanel panel = new JPanel(); frame.setContentPane( panel ); panel.setBorder(BorderFactory.createEmptyBorder(20,20,20,20)); panel.setLayout(new BorderLayout()); JTextPane textPane = new JTextPane(); textPane.setFont( new Font("monospaced", Font.PLAIN, 12) ); textPane.setText("abc"); JScrollPane scrollPane = new JScrollPane(textPane); panel.add(scrollPane); scrollPane.setPreferredSize(new Dimension(300, 250)); LineNumber lineNumber = new LineNumber( textPane ); scrollPane.setRowHeaderView( lineNumber ); frame.pack(); frame.setVisible(true); } }