⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 textarea.java

📁 ErGo是一个很早的Java通用围棋服务器(IGS/NNGS)客户端程序。有全部源码和文档
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
package ergo.ui;

// $Id: TextArea.java,v 1.3 1999/08/13 01:20:11 sigue Exp $

/*
 *  Copyright (C) 1999  Carl L. Gay and Antranig M. Basman.
 *  See the file copyright.txt, distributed with this software,
 *  for further information.
 */

/*
 * To do list:
 *
 * - Make thread safe.
 * - Finish implementing horiz scrolling.
 * - Implement replaceText(), setText(), ...
 * - appendText() shouldn't always end with an implicit \n.
 * - Implement Copy to clipboard.
 * - Resizing the TextCanvas needs to update the number of historyLines
 *   correctly.  Should start a background thread to recalc it, in case
 *   the history is large.  Will have to do some interesting locking
 *   with anything that may modify the history.
 *
 */

import ergo.util.Debug;

import java.util.Vector;
import java.awt.*;
import java.awt.event.AdjustmentListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.MouseListener;

/*
 * Helper classes
 */

/*
 * A HistoryElement represents one line of text delimited by \n.  (The
 * \n is not actually stored.)  It may eventually contain a style-map,
 * i.e. ranges of the line that have a particular text style
 * (font/face/size/color), and perhaps also information about
 * hyperlinks.  (Hey, I can dream can't I?)
 *
 * A HistoryElement may take up more than one physical line on the screen
 * if it is too long and wraps around.  That's where all the complications
 * come in...
 */
class HistoryElement {
  // The text of the element are stored in a char array since we will have
  // to display parts of the string at a time and the Graphics class has
  // no drawString method that takes indices into the string, thus making
  // it necessary to call substring, which would be unacceptable.
  private char[] text;

  // lines stores indices into text (above) where the physical lines
  // that correspond to the history element begin and end.  i.e., if
  // one history element wraps so it's displayed on two physical
  // screen lines then lines contains 1 index which points to the
  // beginning of the second line.  Since the first line always begins
  // at 0 it is not stored.  (Want to save space here since there may
  // be thousands of these...  These being shorts means a history element
  // can't be longer than 32768 chars.)
  private short[] lines = null;

  // Might want to store the line lengths here, to be able to better deal
  // with whitespace at the beginning of wrapped lines.  Otherwise,
  // wrapping nicely (i.e., no extra space at the beginning or end of
  // lines) would be very expensive.
  // e.g., private short[] lengths = null;

  //StyleVector stylemap;

  // For now a history element can have a single color.
  public Color color = Color.black;

  HistoryElement (String s, Color c) {
    text = s.toCharArray();
    color = c;
  }

  public char[] getChars () { return text; }

  public short[] getLines () { return lines; }

  public void setLines (short[] lines) { this.lines = lines; }

  public int getLineOffset (int index) {
    if (index == 0)
      return 0;
    else
      return lines[index - 1];
  }

  public int getLineLength (int index) {
    if (index == 0) {
      if (lines == null || lines.length == 0)
        return text.length;
      else
        return lines[0];
    }
    else {
      if (index < lines.length)
        return lines[index] - lines[index - 1];
      else
        return text.length - lines[index - 1];
    }
  }

}

/*
 * The History class represents all output displayed in the TextCanvas.
 * It is basically just a glorified Vector.
 */
class History {
  private Vector v;
  // Width in pixels of the widest line output to the canvas.
  // Of use to horiz scrollbar in TextArea
  private int widestLine = 0;
  // Number of physical lines (not history elements) in this history.
  private int numLines = 0;

  public History (int initialSize, int sizeIncrement) {
    v = new Vector(initialSize, sizeIncrement);
  }

  public HistoryElement elementAt (int index) {
    return (HistoryElement) v.elementAt(index);
  }

  public int size () { return v.size(); }

  // Return the index of the first element in the history, or -1 if
  // there are no elements yet.  (This will be used for circular buffers.)
  public int startIndex () {
    if (v.size() == 0)
      return 0;
    else
      return -1;
  }

  // Return the index of the last element in the history, or -1 if
  // there are no elements yet.  (This will be used for circular buffers.)
  public int endIndex () {
    return v.size() - 1;
  }

  // Return the index of where the element after i would be stored.
  // (This will be used for circular buffers.)
  public int nextIndex (int i) {
    return i + 1;
  }

  // Return the index of where the element before i would be stored.
  // (This will be used for circular buffers.)
  public int prevIndex (int i) {
    return i - 1;
  }

  // Add an element to the buffer, returning its index.
  // Unfortunately this duplicates some logic in nextIndex (above).
  public int addElement (HistoryElement elem) {
    int index = nextIndex(endIndex());
    v.addElement(elem);
    return index;
  }

  // Invalidate all history elements so their line breaks need to be
  // recomputed.
  public void invalidate () {
    for (int i = 0; i < v.size(); i++)
      elementAt(i).setLines(null);
  }

  // Write it to a stream.  It's the responsibility of the caller
  // to close the stream.  (They might want to add something after.)
  public void save (java.io.PrintWriter outstream) {
    for (int i = 0; i < size(); i++) {
      outstream.print(elementAt(i).getChars());
      outstream.println();
    }
  }

}

/*
 * A TextCanvas object is a multi-line area that displays text with
 * optional line wrapping.  Any variables that refer to "lines" refer
 * to the virtual lines visible to the user.  These are distinct from
 * history elements.  If a history element is longer than the number of
 * columns in the canvas then it wraps to create some number of virtual
 * lines.
 *
 * public appendLine(String)
 *   - Appends the given string to the output history of the canvas
 *     and, if the canvas has not been scrolled up, displays the string.
 * public moveViewportUp(int numLines)
 *   - Scrolls backward in the history the specified number of lines.
 * public moveViewportDown(int numLines)
 *   - Scrolls forward in the history the specified number of lines.
 * public scrollToEnd()
 * public scrollToBeginning()
 * public clearHistory()
 *   - Erase all history elements and clear the canvas.
 */
class TextCanvas extends Canvas {
  private Insets insets = new Insets(1, 3, 1, 3); // top, left, bot, right
  private boolean border = false;
  private int rows;
  private int cols;
  private int width = -1;
  private int height = -1;
  private int insideWidth = -1;
  private int maxLineWidth = 0;	// used for horiz scrolling.
  private Image offscreen = null;
  private Graphics offg = null;
  private boolean wrap = true;  // Wrap long lines to next line?
  private History history;
  private int histSize;
  private int histMax;
  private int tabWidth = 60;	// tab width in pixels
  // The number of lines in the history.  Note that if some lines wrap
  // then this is not the number of history elements!
  private int historyLines = 0;
  private Font font = new Font("Monospaced", Font.PLAIN, 12);

  // The following store the history element at the bottom of the
  // canvas.  hbot is an index into the history, and lbot is an index
  // into the HistoryElement "lines" array.  bottomLine tells what
  // virtual line is at the bottom of the canvas.  i.e., what line
  // corresponds to hbot,lbot.  It is useful for implementing a scrollbar.
  private int hbot;
  private int lbot;
  private int bottomLine;

  // baselines of top and bottom lines, respectively.
  private int ymin = -1;
  private int ymax = -1;


  public TextCanvas (String text, int rows, int columns,
		     int histSize, int histMax, boolean wrap) {
    super();
    this.rows = rows;
    this.cols = columns;
    this.histSize = histSize;
    this.histMax = histMax;
    this.wrap = wrap;
    clearHistory();
    if (text != null)
      appendText(text);
  }

  private boolean isInitialized () {
    return (width != -1);
  }

  public int getRows ()    { return rows; }
  public int getColumns () { return cols; }

  public Insets getInsets ()         { return insets; }
  public void   setInsets (Insets i) { if (i != null) insets = i; }

  public void setBorder (boolean b) { border = b; }

  public void setFont (Font f) {
    if (f != null) {
      super.setFont(f);
      font = f;
      if (offg != null)
	offg.setFont(f);
    }
    else {
      Debug.println("Error: Attempt to set font to null (ignored).");
      Debug.backtrace();
    }
  }

  // Return the width of the widest line drawn on the canvas so far.
  // Note that some history elements may not ever have been rendered
  // after the canvas was resized, so they won't be taken into account.
  // This may be useful for horizontal scrolling.
  public int getMaxLineWidth () { return maxLineWidth; }

  public int getHistoryLines () { return historyLines; }

  public int getBottomDisplayedLine () { return Math.max(0, bottomLine); }

  private Dimension getMySize (int rows, int cols) {
    FontMetrics m = Toolkit.getDefaultToolkit().getFontMetrics(getFont());
    int lineHeight = m.getHeight();
    int charWidth = m.charWidth('m');
    Insets insets = getInsets();
    return new Dimension(insets.top + insets.bottom + charWidth * cols,
			 insets.left + insets.right + lineHeight * rows);
  }

  // Preferred size = rows x columns
  public Dimension getPreferredSize () {
    Dimension d = getMySize(rows, cols);
    //Debug.println("TextCanvas.getPreferredSize returning " + d);
    return d;
  }

  // Minimum size = 1 row x 10 columns
  public Dimension getMinimumSize () { return getMySize(3, 10); }

  public void clearHistory () {
    history = new History(histSize, histSize * 2);
    if (offg != null)
      clearCanvas(offg);
    hbot = lbot = historyLines = 0;
    bottomLine = -1;
  }

  // Recompute the number of lines used by the given element, based
  // on the inside width of the canvas.  Update maxLineWidth while
  // we're at it.
  private short[] computeLines (HistoryElement e, FontMetrics m) {
    short[] lines = e.getLines();
    if (lines == null) {
      if (m == null)
	m = Toolkit.getDefaultToolkit().getFontMetrics(getFont());
      int[] widths = m.getWidths();
      Vector v = new Vector(2, 2);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -