📄 linenumberborder.java~2~
字号:
/*
* 11/18/2004
*
* LineNumberBorder.java - Line numbers for a text area contained
* in an RTextScrollPane.
* Copyright (C) 2004 Robert Futrell
* email@address.com
* www.website.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package org.fife.ui.rtextarea;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JScrollPane;
import javax.swing.border.*;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Element;
import javax.swing.text.View;
import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
/**
* Used by <code>RTextScrollPane</code> to display line numbers for a text
* area. This component is capable of displaying line numbers for any
* <code>RTextArea</code>, with line wrap enabled or disabled. You can also
* choose the line number font, color, and choose whether or not to "highlight"
* the current line number.
*
* @author Robert Futrell
* @version 0.5
*/
class LineNumberBorder
implements Border, CaretListener, DocumentListener,
PropertyChangeListener, ChangeListener {
private static final int MIN_CELL_WIDTH = 24;
private static final int RHS_BORDER_WIDTH = 8;
private static final Color DEFAULT_FOREGROUND = new Color(128, 128, 128);
private RTextArea textArea;
private JScrollPane scrollPane;
private Font font;
private Color foreground;
private Color background;
private int currentLine; // The last line the caret was on.
private int lastY = -1; // Used to check if caret is on a new line when line wrap's enabled.
private Insets insets;
private int cellHeight; // The height of a "cell" for a line number when word wrap is off.
private int ascent; // The ascent to use when painting line numbers.
private int currentNumLines;
/*****************************************************************************/
/**
* Constructs a new <code>LineNumberBorder</code> using default values for
* line number color (gray) and highlighting the current line.
*
* @param scrollPane The scroll pane using this border as the viewport
* border.
* @param textArea The text component for which line numbers will be
* displayed.
*/
public LineNumberBorder(JScrollPane scrollPane, RTextArea textArea) {
this(scrollPane, textArea, DEFAULT_FOREGROUND);
}
/*****************************************************************************/
/**
* Constructs a new <code>LineNumberBorder</code>.
*
* @param scrollPane The scroll pane using this border as the viewport
* border.
* @param textArea The text component for which line numbers will be
* displayed.
* @param numberColor The color to use for the line numbers. If
* <code>null</code>, a default is used.
*/
public LineNumberBorder(JScrollPane scrollPane, RTextArea textArea,
Color numberColor) {
// Remember what text component we're keeping line numbers for.
this.textArea = textArea;
this.scrollPane = scrollPane;
setForeground(numberColor != null ? numberColor : DEFAULT_FOREGROUND);
Color bg = textArea.getBackground();
setBackground(bg == null ? Color.WHITE : bg);
textArea.addCaretListener(this);
textArea.addPropertyChangeListener(this);
scrollPane.getViewport().addChangeListener(this);
textArea.getDocument().addDocumentListener(this);
// Initialize currentLine; otherwise, the current line won't start
// off as highlighted.
currentLine = 1;
setFont(null); // Default font.
insets = new Insets(0, 0, 0, 0);
updateCellHeights();
updateCellWidths();
insertUpdate(null); // Will call updateCellWidths().
}
/*****************************************************************************/
/**
* Called whenever the caret changes position; highlight the correct line
* number.
*
* @param e The caret event.
*/
public void caretUpdate(CaretEvent e) {
int caretPosition = textArea.getCaretPosition();
// We separate the line wrap/no line wrap cases because word wrap can
// make a single line from the model (document) be on multiple lines
// on the screen (in the view); thus, we have to enhance the logic for
// that case a bit - we check the actual y-coordinate of the caret
// when line wrap is enabled. For the no-line-wrap case, getting the
// line number of the caret suffices. This increases efficiency in
// the no-line-wrap case.
if (textArea.getLineWrap() == false) {
int line = textArea.getDocument().getDefaultRootElement().
getElementIndex(caretPosition) + 1;
if (currentLine != line) {
currentLine = line;
scrollPane.repaint();
}
}
else { // lineWrap is enabled; must check actual y-coord. of caret.
try {
Rectangle r = textArea.modelToView(caretPosition);
if (r != null && r.y != lastY) {
lastY = r.y;
currentLine = textArea.getDocument().
getDefaultRootElement().
getElementIndex(caretPosition) + 1;
scrollPane.repaint();
}
}
catch (BadLocationException ble) {
ble.printStackTrace();
}
}
}
/*****************************************************************************/
public void changedUpdate(DocumentEvent e) {}
/*****************************************************************************/
/**
* Returns the background color of the line number list.
*
* @return The background color.
* @see #setBackground
*/
public Color getBackground() {
return background;
}
/*****************************************************************************/
/**
* Returns the insets of this border.
*
* @param c This parameter is ignored.
* @return The insets of this border.
*/
public Insets getBorderInsets(Component c) {
return insets;
}
/*****************************************************************************/
/**
* Returns the bounds of a child view as a rectangle, since
* <code>View</code>s tend to use <code>Shape</code>.
*
* @param parent The parent view of the child whose bounds we're getting.
* @param line The index of the child view.
* @param editorRect Returned from the text area's
* <code>getVisibleEditorRect</code> method.
* @return The child view's bounds.
*/
private static final Rectangle getChildViewBounds(View parent, int line,
Rectangle editorRect) {
Shape alloc = parent.getChildAllocation(line, editorRect);
return alloc instanceof Rectangle ? (Rectangle) alloc :
alloc.getBounds();
}
/*****************************************************************************/
/**
* Returns the font used for the line numbers.
*
* @return The font.
* @see #setFont
*/
public Font getFont() {
return font;
}
/*****************************************************************************/
/**
* Returns the foreground color of the line number list.
*
* @return The foreground color.
* @see #setForeground
*/
public Color getForeground() {
return foreground;
}
/*****************************************************************************/
/**
* Returns the color to use to paint line numbers.
*
* @return The color used when painting line numbers.
* @see #setLineNumberColor
*/
public Color getLineNumberColor() {
return getForeground();
}
/*****************************************************************************/
/**
* Called whenever a character is input (key is typed) in the text
* document we're line-numbering.
*
* @param e The document event.
*/
public void insertUpdate(DocumentEvent e) {
int newNumLines = textArea.getDocument().getDefaultRootElement().
getElementCount();
if (newNumLines > currentNumLines) {
// Adjust the amount of space the line numbers take up,
// if necessary.
if (newNumLines / 10 > currentNumLines / 10) {
updateCellWidths();
}
currentNumLines = newNumLines;
}
}
/*****************************************************************************/
/**
* Returns whether this border is opaque.
*
* @return Whether this border is opaque.
*/
public boolean isBorderOpaque() {
return true;
}
/*****************************************************************************/
/**
* Paints the line numbers. If word wrap is enabled, the gruntwork is
* passed on to another method.
*
* @param c The text area.
* @param g The graphics context.
* @param x The x-coordinate of the border.
* @param y The y-coordinate of the border.
* @param width The width of the border.
* @param height The height of the border.
* @see #paintWrappedLineNumbers
*/
public void paintBorder(Component c, Graphics g, int x, int y, int width,
int height) {
Element root = textArea.getDocument().getDefaultRootElement();
Rectangle visibleRect = textArea.getVisibleRect();
if (visibleRect == null) {
return;
}
// Fill in the background the same color as the text component.
g.setColor(getBackground());
g.fillRect(x, y, insets.left, height);
g.setFont(font);
if (textArea.getLineWrap() == true) {
paintWrappedLineNumbers(g, root, x, y, visibleRect);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -