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 + -
显示快捷键?