📄 textarea.java
字号:
int widthsofar = 0;
short prevwhite = 0;
char[] text = e.getChars();
short i = 0;
short rightmost = 0;
while (i < text.length) {
char c = text[i];
int charwidth = (int) c < 256 ? widths[(int) c] : m.charWidth(0x4E00);
widthsofar += charwidth;
if (i - prevwhite > 0) { // don't ever wrap line before 1st char
boolean iswhite = Character.isWhitespace(c);
if (widthsofar >= insideWidth) {
if (prevwhite != 0 && !iswhite) {
v.addElement(new Short(prevwhite));
// start computing next line at prevwhite.
i = prevwhite;
}
else {
v.addElement(new Short(i));
rightmost = i;
}
maxLineWidth = Math.max(maxLineWidth, widthsofar - charwidth);
widthsofar = 0;
}
if (iswhite)
prevwhite = i;
}
++i;
}
lines = new short[v.size()];
for (int j = 0; j < lines.length; j++)
lines[j] = ((Short) v.elementAt(j)).shortValue();
e.setLines(lines);
// Add 1 to historyLines for each *extra* line displayed.
// Remember that lines doesn't contain an entry for the 1st line.
historyLines += lines.length;
}
return lines;
}
// Get the number of lines in the given HistoryElement.
private int numLines (HistoryElement e, FontMetrics m) {
if (wrap) {
short[] lines = computeLines(e, m);
return lines.length + 1;
}
else
return 1; // no line wrap. 1 line/element
}
private void invalidateHistory () {
history.invalidate();
maxLineWidth = 0;
// historyLines gets reset to this approximation and gets incrementally
// updated to be more accurate.
historyLines = history.size();
}
public void scrollTo (int linenum) {
int linemax = wrap ? (historyLines - 1) : (history.size() - 1);
linenum = Math.max(0, Math.min(linenum, linemax));
/***
+++ Don't second guess the caller. Need to fix TextArea for this.
if (linenum < getRows() - 1 && linemax >= getRows() - 1)
linenum = getRows() - 1;
***/
if (wrap) {
// In the normal case (?) the user will be scrolling by a page
// or less, so scanning from bottomLine to linenum shouldn't be
// expensive. +++ An optimization would be to check whether
// linenum is closer to 0 or linemax than it is to bottomLine
// and if so, scan from there instead.
int[] vals = findLineRelative(hbot, lbot, linenum - bottomLine);
hbot = vals[0];
lbot = vals[1];
bottomLine = vals[2];
}
else {
bottomLine = linenum;
hbot = linenum;
lbot = 0;
}
redisplay();
}
// Go backward one page in the history. Find the line that is
// rows-1 lines before hbot/lbot and put it at hbot/lbot.
public void pageUp () {
moveViewportUp(rows - 1);
}
// Go forward one page in the history.
public void pageDown () {
moveViewportDown(rows - 1);
}
// Find the line nlines distant from startIndex/startLine.
// nlines may be positive or negative (or zero).
private int[] findLineRelative (int startIndex, int startLine, int nlines) {
//Debug.println("findLineRelative: " + startIndex + "," + startLine
// + "," + bottomLine + ", delta=" + nlines);
int[] result = new int[3]; // multiple value kludge
int requested = nlines;
if (!wrap) {
result[0] = Math.min(Math.max(0, startIndex + nlines),
history.size() - 1);
result[1] = 0;
result[2] = result[0];
}
else { // wrapping
HistoryElement elem = history.elementAt(startIndex);
FontMetrics metrics = Toolkit.getDefaultToolkit().getFontMetrics(offg.getFont());
int hsize = history.size();
//if (startLine >= numLines(elem, metrics))
//Debug.println("findLineRelative called with invalid arg: startLine");
if (nlines > 0) {
while (nlines > 0) {
--nlines;
++startLine;
if (startLine >= numLines(elem, metrics)) {
startLine = 0;
++startIndex;
if (startIndex >= hsize) {
startIndex = hsize - 1;
startLine = numLines(elem, metrics) - 1;
++nlines; // undo the previous decrement; it was too much.
break;
}
}
elem = history.elementAt(startIndex);
}
}
else { // nlines <= 0
while (nlines < 0) {
++nlines;
--startLine;
if (startLine < 0) {
--startIndex;
if (startIndex < 0) {
startIndex = 0;
startLine = 0;
--nlines; // undo the previous increment; it was too much.
break;
}
elem = history.elementAt(startIndex);
startLine = numLines(elem, metrics) - 1;
}
}
}
result[0] = startIndex; // new hbot
result[1] = startLine; // new lbot
result[2] = bottomLine + (requested - nlines); // new bottomLine value
}
//Debug.println("findLineRelative found "
// + result[0] + "," + result[1] + "," + result[2]);
return result;
}
/*
* Scrolling
*
* Note: In Java terminology scrolling UP means moving the viewport
* onto the window history UP, which moves the window history DOWN.
* I just mention this because I've always thought of it the other
* way around...
*/
// Move forward in the output history.
// +++ Should use copyArea when nlines is small, rather than
// just calling redisplay()?
public void moveViewportDown (int nlines) {
if (history.size() > 0) {
//Debug.println("moveViewportDown(" + nlines + ") from " + hbot + "," + lbot);
int[] pos = findLineRelative(hbot, lbot, nlines);
hbot = pos[0];
lbot = pos[1];
bottomLine = pos[2];
redisplay();
}
}
// Move backward in the output history.
public void moveViewportUp (int nlines) {
if (bottomLine - nlines < rows - 1)
moveViewportToBeginning();
else
moveViewportDown(-nlines);
}
public void moveViewportToBeginning () {
hbot = lbot = bottomLine = 0;
scrollTo(rows - 1);
}
public void moveViewportToEnd () {
hbot = history.size() - 1;
HistoryElement elem = history.elementAt(hbot);
lbot = numLines(elem, Toolkit.getDefaultToolkit().getFontMetrics(getFont())) - 1;
bottomLine = historyLines;
redisplay();
}
// atBottom is true if the viewport fully contains the last line in the
// history. In other words, if the user has not scrolled backward at
// all. This controls whether scrolling is done automatically when
// appendLine() is called.
private boolean atBottom () {
int last = history.endIndex();
if (last == -1 || !isInitialized())
return true;
else {
//Debug.println("atBottom: " + hbot + "," + lbot + "," + last + ","
// + (numLines(history.elementAt(last), null) - 1));
return (last == hbot &&
(lbot + 1) == numLines(history.elementAt(last), null));
}
}
// Kludge to deal with tabs. Assumes tab stops every 8 chars.
private String expandTabs (String s) {
int i = s.indexOf('\t');
if (i == -1)
return s; // no tabs, just return it
else {
int len = s.length();
StringBuffer b = new StringBuffer(len + 20); // 20 reasonable?
for (int j = 0; j < len; j++) {
char c = s.charAt(j);
if (c == '\t') {
int nspaces = 8 - (b.length() % 8);
for (int k = 0; k < nspaces; k++)
b.append(' ');
}
else
b.append(c);
}
return b.toString();
}
}
// Append a string (that contains no Newline chars) to the end of
// the TextCanvas. The string may be displayed on > 1 physical line.
public void appendLine (String str, boolean repaint, Color color) {
synchronized (this) {
str = expandTabs(str);
HistoryElement elem = new HistoryElement(str, color);
// If offg is null the canvas hasn't been made visible yet. When
// it does become visible we want it to be at the end of the history
// so set hbot.
if (offg == null) {
hbot = history.addElement(elem);
}
// If not at the bottom of the history, then the user has scrolled
// back. Just tack the new element onto the end, without setting hbot.
else if (!atBottom()) {
history.addElement(elem);
}
else {
hbot = history.addElement(elem);
int nlines = numLines(elem, Toolkit.getDefaultToolkit()
.getFontMetrics(offg.getFont()));
bottomLine += nlines;
lbot = wrap ? (nlines - 1) : 0;
}
historyLines += 1; // if it wraps, computeLines will add more to this.
if (repaint)
repaint();
} // synchronized
}
/**
* Appends the given text to the end of the current text. If the
* viewport is currently at the end of the TextCanvas the viewport
* is moved down and the new text displayed at the end. Otherwise
* the new text is added to the end without changing to contents
* of the viewport.
*
* @param text the text to insert
*/
public void appendText (String text) {
appendText(text, Color.black);
}
public void appendText (String text, Color color) {
int saved = 0;
int length = text.length();
for (int i = saved; i <= length; i++) {
if (i >= length)
appendLine(text.substring(saved), true, color);
else if (text.charAt(i) == '\n') {
appendLine(text.substring(saved, i), true, color);
if (i + 1 >= length)
break;
saved = i + 1; // skip the Newline char.
}
}
// repaint not needed since passed true to appendLine()
//repaint();
}
/**
* Inserts the specified text at the specified position.
* @param str the text to insert.
* @param pos the position at which to insert.
*/
public void insertText (String str, int pos) {
// ---*** Fill this in.
}
/**
* Replaces text from the indicated start to end position with the
* new text specified.
*
* @param str the text to use as the replacement.
* @param start the start position.
* @param end the end position.
*/
public void replaceText (String str, int start, int end) {
// ---*** Fill this in.
}
public void clearCanvas (Graphics g) {
g.setColor(getBackground());
g.fillRect(0, 0, width, height);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -