jedittextarea.java
来自「java写的多功能文件编辑器」· Java 代码 · 共 2,487 行 · 第 1/5 页
JAVA
2,487 行
/* * JEditTextArea.java - jEdit's text component * Copyright (C) 1999, 2000 Slava Pestov * Portion Copyrights (C) 2001-2003 Romain Guy * * 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.gjt.sp.jedit.textarea;import javax.swing.event.*;import javax.swing.text.*;import javax.swing.undo.*;import javax.swing.*;import java.awt.datatransfer.*;import java.awt.event.*;import java.awt.*;import java.awt.font.*;import java.util.Enumeration;import java.util.Vector;import org.gjt.sp.jedit.syntax.*;import org.gjt.sp.jedit.gui.KeyEventWorkaround;import org.jext.JextFrame;import org.jext.JextTextArea;/** * jEdit's text area component. It is more suited for editing program * source code than JEditorPane, because it drops the unnecessary features * (images, variable-width lines, and so on) and adds a whole bunch of * useful goodies such as: * <ul> * <li>More flexible key binding scheme * <li>Supports macro recorders * <li>Rectangular selection * <li>Bracket highlighting * <li>Syntax highlighting * <li>Command repetition * <li>Block caret can be enabled * </ul> * It is also faster and doesn't have as many problems. It can be used * in other applications; the only other part of jEdit it depends on is * the syntax package.<p> * * To use it in your app, treat it like any other component, for example: * <pre>JEditTextArea ta = new JEditTextArea(); * ta.setTokenMarker(new JavaTokenMarker()); * ta.setText("public class Test {\n" * + " public static void main(String[] args) {\n" * + " System.out.println(\"Hello World\");\n" * + " }\n" * + "}");</pre> * * @author Slava Pestov * @version $Id: JEditTextArea.java,v 1.10 2003/06/30 17:31:08 blaisorblade Exp $ */public class JEditTextArea extends JComponent{ private JextFrame view; /** * Adding components with this name to the text area will place * them left of the horizontal scroll bar. In jEdit, the status * bar is added this way. */ public static String LEFT_OF_SCROLLBAR = "los"; /** * Creates a new JEditTextArea with the default settings. */ public JEditTextArea(JextFrame view) { this(view, TextAreaDefaults.getDefaults()); } /** * Creates a new JEditTextArea with the specified settings. * @param defaults The default settings */ public JEditTextArea(JextFrame view, TextAreaDefaults defaults) { this.view = view; // Enable the necessary events enableEvents(AWTEvent.KEY_EVENT_MASK); // Initialize some misc. stuff painter = new TextAreaPainter(this, defaults); gutter = new Gutter(this, defaults); documentHandler = new DocumentHandler(); listenerList = new EventListenerList(); caretEvent = new MutableCaretEvent(); bracketLine = bracketPosition = -1; blink = true; lineSegment = new Segment(); // Initialize the GUI setLayout(new ScrollLayout()); add(LEFT, gutter); add(CENTER, painter); add(RIGHT, vertical = new JScrollBar(JScrollBar.VERTICAL)); add(BOTTOM, horizontal = new JScrollBar(JScrollBar.HORIZONTAL)); // Add some event listeners vertical.addAdjustmentListener(new AdjustHandler()); horizontal.addAdjustmentListener(new AdjustHandler()); painter.addComponentListener(new ComponentHandler()); painter.addMouseListener(new MouseHandler()); painter.addMouseMotionListener(new DragHandler()); addFocusListener(new FocusHandler()); // Load the defaults editable = defaults.editable; caretVisible = defaults.caretVisible; caretBlinks = defaults.caretBlinks; electricScroll = defaults.electricScroll; popup = defaults.popup; setDocument(new SyntaxDocument()); // We don't seem to get the initial focus event? focusedComponent = this; } public boolean getFocusTraversalKeysEnabled() { return false; } public InputHandler getInputHandler() { return view.getInputHandler(); } /** * Returns if this component can be traversed by pressing * the Tab key. This returns false. */ public final boolean isManagingFocus() { return true; } /** * Returns 0,0 for split pane compatibility. */ public final Dimension getMinimumSize() { return new Dimension(0, 0); } /** * Returns the object responsible for painting this text area. */ public final TextAreaPainter getPainter() { return painter; } /** * Returns the gutter to the left of the text area or null if the gutter * is disabled */ public final Gutter getGutter() { return gutter; } /** * Returns true if the caret is blinking, false otherwise. */ public final boolean isCaretBlinkEnabled() { return caretBlinks; } /** * Toggles caret blinking. * @param caretBlinks True if the caret should blink, false otherwise */ public void setCaretBlinkEnabled(boolean caretBlinks) { this.caretBlinks = caretBlinks; if (!caretBlinks) blink = false; painter.invalidateSelectedLines(); } /** * Returns true if the caret is visible, false otherwise. */ public final boolean isCaretVisible() { return (!caretBlinks || blink) && caretVisible; } /** * Sets if the caret should be visible. * @param caretVisible True if the caret should be visible, false * otherwise */ public void setCaretVisible(boolean caretVisible) { this.caretVisible = caretVisible; blink = true; painter.invalidateSelectedLines(); } /** * Blinks the caret. */ public final void blinkCaret() { if (caretBlinks) { blink = !blink; painter.invalidateSelectedLines(); } else blink = true; } /** * Returns the number of lines from the top and button of the * text area that are always visible. */ public final int getElectricScroll() { return electricScroll; } /** * Sets the number of lines from the top and bottom of the text * area that are always visible * @param electricScroll The number of lines always visible from * the top or bottom */ public final void setElectricScroll(int electricScroll) { this.electricScroll = electricScroll; } /** * Updates the state of the scroll bars. This should be called * if the number of lines in the document changes, or when the * size of the text are changes. */ public void updateScrollBars() { if (vertical != null && visibleLines != 0) { int lineCount = getLineCount(); if (firstLine < 0) { setFirstLine(0); return; } else if (lineCount < firstLine + visibleLines) { int newFirstLine = Math.max(0, lineCount - visibleLines); if (newFirstLine != firstLine) { setFirstLine(newFirstLine); return; } } vertical.setValues(firstLine, visibleLines, 0, getLineCount()); vertical.setUnitIncrement(2); vertical.setBlockIncrement(visibleLines); } int width = painter.getWidth(); if (horizontal != null && width != 0) { maxHorizontalScrollWidth = 0; painter.repaint(); horizontal.setUnitIncrement(painter.getFontMetrics().charWidth('w')); horizontal.setBlockIncrement(width / 2); } } /** * Returns the line displayed at the text area's origin. */ public final int getFirstLine() { return firstLine; } /** * Sets the line displayed at the text area's origin without * updating the scroll bars. */ public void setFirstLine(int firstLine) { if (firstLine == this.firstLine) return; int oldFirstLine = this.firstLine; this.firstLine = firstLine; maxHorizontalScrollWidth = 0; if (firstLine != vertical.getValue()) updateScrollBars(); painter.repaint(); gutter.repaint(); } /** * Returns the number of lines visible in this text area. */ public final int getVisibleLines() { return visibleLines; } /** * Recalculates the number of visible lines. This should not * be called directly. */ public final void recalculateVisibleLines() { if (painter == null) return; int height = painter.getHeight(); int lineHeight = painter.getFontMetrics().getHeight(); int oldVisibleLines = visibleLines; visibleLines = height / lineHeight; updateScrollBars(); } void updateMaxHorizontalScrollWidth() { int _maxHorizontalScrollWidth = getTokenMarker().getMaxLineWidth(firstLine, visibleLines); if (_maxHorizontalScrollWidth != maxHorizontalScrollWidth) { maxHorizontalScrollWidth = _maxHorizontalScrollWidth; horizontal.setValues(-horizontalOffset, painter.getWidth(), 0, maxHorizontalScrollWidth + painter.getFontMetrics().charWidth('w')); } } /** * Returns the horizontal offset of drawn lines. */ public final int getHorizontalOffset() { return horizontalOffset; } /** * Sets the horizontal offset of drawn lines. This can be used to * implement horizontal scrolling. * @param horizontalOffset offset The new horizontal offset */ public void setHorizontalOffset(int horizontalOffset) { if (horizontalOffset == this.horizontalOffset) return; this.horizontalOffset = horizontalOffset; if (horizontalOffset != horizontal.getValue()) updateScrollBars(); painter.repaint(); } /** * A fast way of changing both the first line and horizontal * offset. * @param firstLine The new first line * @param horizontalOffset The new horizontal offset * @return True if any of the values were changed, false otherwise */ public boolean setOrigin(int firstLine, int horizontalOffset) { boolean changed = false; int oldFirstLine = this.firstLine; if (horizontalOffset != this.horizontalOffset) { this.horizontalOffset = horizontalOffset; changed = true; } if (firstLine != this.firstLine) { this.firstLine = firstLine; changed = true; } if (changed) { updateScrollBars(); painter.repaint(); gutter.repaint(); } return changed; } /** * Ensures that the caret is visible by scrolling the text area if * necessary. * @return True if scrolling was actually performed, false if the * caret was already visible */ public boolean scrollToCaret() { int line = getCaretLine(); int lineStart = getLineStartOffset(line); int offset = Math.max(0, Math.min(getLineLength(line) - 1, getCaretPosition() - lineStart)); return scrollTo(line, offset); } /** * Ensures that the specified line and offset is visible by scrolling * the text area if necessary. * @param line The line to scroll to * @param offset The offset in the line to scroll to * @return True if scrolling was actually performed, false if the * line and offset was already visible */ public boolean scrollTo(int line, int offset) { // visibleLines == 0 before the component is realized // we can't do any proper scrolling then, so we have // this hack... if (visibleLines == 0) { setFirstLine(Math.max(0, line - electricScroll)); return true; } int newFirstLine = firstLine; int newHorizontalOffset = horizontalOffset; if (line < firstLine + electricScroll) { newFirstLine = Math.max(0, line - electricScroll); } else if (line + electricScroll >= firstLine + visibleLines) { newFirstLine = (line - visibleLines) + electricScroll + 1; if (newFirstLine + visibleLines >= getLineCount()) newFirstLine = getLineCount() - visibleLines; if (newFirstLine < 0) newFirstLine = 0; } int x = offsetToX(line, offset); int width = painter.getFontMetrics().charWidth('w'); if (x < 0) { newHorizontalOffset = Math.min(0, horizontalOffset - x + width + 5); } else if (x + width >= painter.getWidth()) { newHorizontalOffset = horizontalOffset + (painter.getWidth() - x) - width - 5; } return setOrigin(newFirstLine, newHorizontalOffset); } /** * Converts a line index to a y co-ordinate. * @param line The line */ public int lineToY(int line) { FontMetrics fm = painter.getFontMetrics(); return (line - firstLine) * fm.getHeight() - (fm.getLeading() + fm.getMaxDescent()); } /** * Converts a y co-ordinate to a line index. * @param y The y co-ordinate */ public int yToLine(int y) { FontMetrics fm = painter.getFontMetrics(); int height = fm.getHeight(); return Math.max(0, Math.min(getLineCount() - 1, y / height + firstLine)); } /** * Converts an offset in a line into an x co-ordinate. * @param line The line * @param offset The offset, from the start of the line */ public int offsetToX(int line, int offset)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?