📄 jedittextarea.java
字号:
newStart = end;
newEnd = start;
newBias = true;
}
if (newStart < 0 || newEnd > getDocumentLength())
{
throw new IllegalArgumentException("Bounds out of"
+ " range: " + newStart + "," +
newEnd);
}
// If the new position is the same as the old, we don't
// do all this crap, however we still do the stuff at
// the end (clearing magic position, scrolling)
if (newStart != selectionStart || newEnd != selectionEnd
|| newBias != biasLeft)
{
final int newStartLine = getLineOfOffset(newStart);
final int newEndLine = getLineOfOffset(newEnd);
if (painter.isBracketHighlightEnabled())
{
if (bracketLine != -1)
{
painter.invalidateLine(bracketLine);
}
updateBracketHighlight(end);
if (bracketLine != -1)
{
painter.invalidateLine(bracketLine);
}
}
painter.invalidateLineRange(selectionStartLine, selectionEndLine);
painter.invalidateLineRange(newStartLine, newEndLine);
document.addUndoableEdit(new CaretUndo(selectionStart, selectionEnd));
selectionStart = newStart;
selectionEnd = newEnd;
selectionStartLine = newStartLine;
selectionEndLine = newEndLine;
biasLeft = newBias;
fireCaretEvent();
}
// When the user is typing, etc, we don't want the caret
// to blink
blink = true;
caretTimer.restart();
// Disable rectangle select if selection start = selection end
if (selectionStart == selectionEnd)
{
rectSelect = false;
}
// Clear the `magic' caret position used by up/down
magicCaret = -1;
scrollToCaret();
}
/**
* Returns the selected text, or null if no selection is active.
*/
private String getSelectedText ()
{
if (selectionStart == selectionEnd)
{
return null;
}
if (rectSelect)
{
// Return each row of the selection on a new line
final Element map = document.getDefaultRootElement();
int start = selectionStart - map.getElement(selectionStartLine)
.getStartOffset();
int end = selectionEnd - map.getElement(selectionEndLine)
.getStartOffset();
// Certain rectangles satisfy this condition...
if (end < start)
{
final int tmp = end;
end = start;
start = tmp;
}
final StringBuffer buf = new StringBuffer();
final Segment seg = new Segment();
for (int i = selectionStartLine; i <= selectionEndLine; i++)
{
final Element lineElement = map.getElement(i);
int lineStart = lineElement.getStartOffset();
final int lineEnd = lineElement.getEndOffset() - 1;
lineStart = Math.min(lineStart + start, lineEnd);
final int lineLen = Math.min(end - start, lineEnd - lineStart);
getText(lineStart, lineLen, seg);
buf.append(seg.array, seg.offset, seg.count);
if (i != selectionEndLine)
{
buf.append('\n');
}
}
return buf.toString();
}
else
{
return getText(selectionStart,
selectionEnd - selectionStart);
}
}
/**
* Replaces the selection with the specified text.
*
* @param selectedText The replacement text for the selection
*/
public final void setSelectedText (final String selectedText)
{
if (!editable)
{
throw new InternalError("Text component"
+ " read only");
}
document.beginCompoundEdit();
try
{
if (rectSelect)
{
final Element map = document.getDefaultRootElement();
int start = selectionStart - map.getElement(selectionStartLine)
.getStartOffset();
int end = selectionEnd - map.getElement(selectionEndLine)
.getStartOffset();
// Certain rectangles satisfy this condition...
if (end < start)
{
final int tmp = end;
end = start;
start = tmp;
}
int lastNewline = 0;
int currNewline = 0;
for (int i = selectionStartLine; i <= selectionEndLine; i++)
{
final Element lineElement = map.getElement(i);
final int lineStart = lineElement.getStartOffset();
final int lineEnd = lineElement.getEndOffset() - 1;
final int rectStart = Math.min(lineEnd, lineStart + start);
document.remove(rectStart, Math.min(lineEnd - rectStart,
end - start));
if (selectedText == null)
{
continue;
}
currNewline = selectedText.indexOf('\n', lastNewline);
if (currNewline == -1)
{
currNewline = selectedText.length();
}
document.insertString(rectStart, selectedText
.substring(lastNewline, currNewline), null);
lastNewline = Math.min(selectedText.length(),
currNewline + 1);
}
if (selectedText != null &&
currNewline != selectedText.length())
{
final int offset = map.getElement(selectionEndLine)
.getEndOffset() - 1;
document.insertString(offset, "\n", null);
document.insertString(offset + 1, selectedText
.substring(currNewline + 1), null);
}
}
else
{
document.remove(selectionStart,
selectionEnd - selectionStart);
if (selectedText != null)
{
document.insertString(selectionStart,
selectedText, null);
}
}
}
catch (BadLocationException bl)
{
bl.printStackTrace();
throw new InternalError("Cannot replace"
+ " selection");
}
// No matter what happends... stops us from leaving document
// in a bad state
finally
{
document.endCompoundEdit();
}
setCaretPosition(selectionEnd);
}
/**
* Returns true if this text area is editable, false otherwise.
*/
public final boolean isEditable ()
{
return editable;
}
/**
* Sets if this component is editable.
*
* @param editable True if this text area should be editable, false otherwise
*/
public final void setEditable (final boolean editable)
{
this.editable = editable;
}
/**
* Returns the right click popup menu.
*/
public final JPopupMenu getRightClickPopup ()
{
return popup;
}
/**
* Sets the right click popup menu.
*
* @param popup The popup
*/
public final void setRightClickPopup (final JPopupMenu popup)
{
this.popup = popup;
}
/**
* Returns the `magic' caret position. This can be used to preserve the column position
* when moving up and down lines.
*/
public final int getMagicCaretPosition ()
{
return magicCaret;
}
/**
* Sets the `magic' caret position. This can be used to preserve the column position
* when moving up and down lines.
*
* @param magicCaret The magic caret position
*/
public final void setMagicCaretPosition (final int magicCaret)
{
this.magicCaret = magicCaret;
}
/**
* Similar to <code>setSelectedText()</code>, but overstrikes the appropriate number of
* characters if overwrite mode is enabled.
*
* @param str The string
* @see #setSelectedText(java.lang.String)
* @see #isOverwriteEnabled()
*/
public final void overwriteSetSelectedText (final String str)
{
// Don't overstrike if there is a selection
if (!overwrite || selectionStart != selectionEnd)
{
setSelectedText(str);
return;
}
// Don't overstrike if we're on the end of
// the line
final int caret = getCaretPosition();
final int caretLineEnd = getLineEndOffset(getCaretLine());
if (caretLineEnd - caret <= str.length())
{
setSelectedText(str);
return;
}
document.beginCompoundEdit();
try
{
document.remove(caret, str.length());
document.insertString(caret, str, null);
}
catch (BadLocationException bl)
{
bl.printStackTrace();
}
finally
{
document.endCompoundEdit();
}
}
/**
* Returns true if overwrite mode is enabled, false otherwise.
*/
public final boolean isOverwriteEnabled ()
{
return overwrite;
}
/**
* Sets if overwrite mode should be enabled.
*
* @param overwrite True if overwrite mode should be enabled, false otherwise.
*/
public final void setOverwriteEnabled (final boolean overwrite)
{
this.overwrite = overwrite;
painter.invalidateSelectedLines();
}
/**
* Returns true if the selection is rectangular, false otherwise.
*/
public final boolean isSelectionRectangular ()
{
return rectSelect;
}
/**
* Sets if the selection should be rectangular.
*
* @param rectSelect True if the selection should be rectangular, false otherwise.
*/
public final void setSelectionRectangular (final boolean rectSelect)
{
this.rectSelect = rectSelect;
painter.invalidateSelectedLines();
}
/**
* Returns the position of the highlighted bracket (the bracket matching the one before
* the caret)
*/
public final int getBracketPosition ()
{
return bracketPosition;
}
/**
* Returns the line of the highlighted bracket (the bracket matching the one before the
* caret)
*/
public final int getBracketLine ()
{
return bracketLine;
}
/**
* Adds a caret change listener to this text area.
*
* @param listener The listener
*/
public final void addCaretListener (final CaretListener listener)
{
listenerList.add(CaretListener.class, listener);
}
/**
* Removes a caret change listener from this text area.
*
* @param listener The listener
*/
public final void removeCaretListener (final CaretListener listener)
{
listenerList.remove(CaretListener.class, listener);
}
/**
* Deletes the selected text from the text area and places it into the clipboard.
*/
public final void cut ()
{
if (editable)
{
copy();
setSelectedText("");
}
}
/**
* Places the selected text into the clipboard.
*/
public final void copy ()
{
if (selectionStart != selectionEnd)
{
final Clipboard clipboard = getToolkit().getSystemClipboard();
final String selection = getSelectedText();
final int repeatCount = inputHandler.getRepeatCount();
final StringBuffer buf = new StringBuffer();
for (int i = 0; i < repeatCount; i++)
{
buf.append(selection);
}
clipboard.setContents(new StringSelection(buf.toString()), null);
}
}
/**
* Inserts the clipboard contents into the text.
*/
public final void paste ()
{
if (editable)
{
final Clipboard clipboard = getToolkit().getSystemClipboard();
try
{
// The MacOS MRJ doesn't convert \r to \n,
// so do it here
String selection = ((String) clipboard
.getContents(this).getTransferData(DataFlavor.stringFlavor))
.replace('\r', '\n');
final int repeatCount = inputHandler.getRepeatCount();
final StringBuffer buf = new StringBuffer();
for (int i = 0; i < repeatCount; i++)
{
buf.append(selection);
}
selection = buf.toString();
setSelectedText(selection);
}
catch (Exception e)
{
getToolkit().beep();
System.err.println("Clipboard does not"
+ " contain a string");
}
}
}
/**
* Called by the AWT when this component is removed from it's parent. This stops clears
* the currently focused component.
*/
public final void removeNotify ()
{
super.removeNotify();
if (focusedComponent == this)
{
focusedComponent = null;
}
}
/**
* Forwards key events directly to the input handler. This is slightly faster than using
* a KeyListener because some Swing overhead is avoided.
*/
public final void processKeyEvent (final KeyEvent evt)
{
if (inputHandler == null)
{
return;
}
switch (evt.getID())
{
case KeyEvent.KEY_TYPED:
inputHandler.keyTyped(evt);
break;
case KeyEvent.KEY_PRESSED:
inputHandler.keyPressed(evt);
break;
case KeyEvent.KEY_RELEASED:
inputHandler.keyReleased(evt);
break;
}
}
// protected members
private static final String CENTER = "center";
private static final String RIGHT = "right";
private static final String BOTTOM = "bottom";
private static JEditTextArea focusedComponent;
private static Timer caretTimer;
private TextAreaPainter painter;
private JPopupMenu popup;
private EventListenerList listenerList;
private MutableCaretEvent caretEvent;
private boolean caretBlinks;
private boolean caretVisible;
private boolean blink;
private boolean editable;
private int firstLine;
private int visibleLines;
private int electricScroll;
private int horizontalOffset;
private JScrollBar vertical;
private JScrollBar horizontal;
private boolean scrollBarsInitialized;
private InputHandler inputHandler;
private SyntaxDocument document;
private DocumentHandler documentHandler;
private Segment lineSegment;
private int selectionStart;
private int selectionStartLine;
private int selectionEnd;
private int selectionEndLine;
private boolean biasLeft;
private int bracketPosition;
private int bracketLine;
private int magicCaret;
private boolean overwrite;
private boolean rectSelect;
private void fireCaretEvent ()
{
final Object[] listeners = listenerList.getListenerList();
for (int i = listeners.length - 2; i >= 0; i--)
{
if (listeners[i] == CaretListener.class)
{
((CaretListener) listeners[i + 1]).caretUpdate(caretEvent);
}
}
}
private void updateBracketHighlight (final int newCaretPosition)
{
if (newCaretPosition == 0)
{
bracketPosition = bracketLine = -1;
return;
}
try
{
final int offset = TextUtilities.findMatchingBracket(document, newCaretPosition - 1);
if (offset != -1)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -