11 package net.sf.gridarta.textedit.textarea;
13 import java.awt.AWTEvent;
14 import java.awt.Adjustable;
16 import java.awt.datatransfer.Clipboard;
17 import java.awt.datatransfer.DataFlavor;
18 import java.awt.datatransfer.StringSelection;
19 import java.awt.datatransfer.UnsupportedFlavorException;
20 import java.awt.event.ActionEvent;
21 import java.awt.event.ActionListener;
22 import java.awt.event.AdjustmentEvent;
23 import java.awt.event.AdjustmentListener;
24 import java.awt.event.ComponentAdapter;
25 import java.awt.event.ComponentEvent;
26 import java.awt.event.FocusEvent;
27 import java.awt.event.FocusListener;
28 import java.awt.event.InputEvent;
29 import java.awt.event.KeyEvent;
30 import java.awt.event.MouseAdapter;
31 import java.awt.event.MouseEvent;
32 import java.awt.event.MouseMotionListener;
33 import java.awt.event.MouseWheelEvent;
34 import java.io.IOException;
35 import java.lang.reflect.Field;
36 import java.lang.reflect.InvocationTargetException;
37 import java.lang.reflect.Method;
38 import java.util.HashSet;
40 import javax.swing.JComponent;
41 import javax.swing.JPopupMenu;
42 import javax.swing.JScrollBar;
43 import javax.swing.KeyStroke;
44 import javax.swing.SwingUtilities;
45 import javax.swing.Timer;
46 import javax.swing.event.DocumentEvent;
47 import javax.swing.event.DocumentListener;
48 import javax.swing.text.BadLocationException;
49 import javax.swing.text.Document;
50 import javax.swing.text.Segment;
51 import javax.swing.undo.AbstractUndoableEdit;
52 import javax.swing.undo.CannotRedoException;
53 import javax.swing.undo.CannotUndoException;
54 import javax.swing.undo.UndoableEdit;
55 import org.apache.log4j.Category;
56 import org.apache.log4j.Logger;
57 import org.jetbrains.annotations.NotNull;
58 import org.jetbrains.annotations.Nullable;
115 CARET_TIMER.setInitialDelay(500);
129 private final JScrollBar
vertical =
new JScrollBar(Adjustable.VERTICAL);
132 private final JScrollBar
horizontal =
new JScrollBar(Adjustable.HORIZONTAL);
162 enableEvents(AWTEvent.KEY_EVENT_MASK);
165 caret =
new TextAreaCaret(defaults.getCaretVisible(), defaults.getCaretBlinks());
167 config =
new TextAreaConfig(defaults.getEditable(), defaults.getElectricScroll());
168 painter =
new TextAreaPainter(
this, selection, caret, defaults, brackets, config, paintInvalid);
169 painter.recalculateVisibleLines();
182 painter.addMouseListener(mouseHandler);
183 painter.addMouseWheelListener(mouseHandler);
188 inputHandler = defaults.getInputHandler();
194 popup = defaults.getPopup();
200 focusedComponent =
this;
231 final Set<KeyStroke> forwardTraversalKeys =
new HashSet<>();
232 forwardTraversalKeys.add(KeyStroke.getKeyStroke(
"control TAB"));
235 final Field field = Class.forName(
"java.awt.KeyboardFocusManager").getField(
"FORWARD_TRAVERSAL_KEYS");
236 final Integer value = field.getInt(field);
238 for (
final Method method : getClass().getMethods()) {
240 if (method.getName().equalsIgnoreCase(
"setFocusTraversalKeys")) {
241 method.invoke(
this, value, forwardTraversalKeys);
245 }
catch (
final ClassNotFoundException ignored) {
247 }
catch (
final IllegalAccessException ignored) {
249 }
catch (
final InvocationTargetException ignored) {
251 }
catch (
final NoSuchFieldException ignored) {
261 public void setFont(@NotNull
final Font font) {
306 if (visibleLines != 0) {
309 vertical.setUnitIncrement(1);
310 vertical.setBlockIncrement(visibleLines);
313 final int width = painter.getWidth();
318 horizontal.setBlockIncrement(width / 2);
338 if (firstLine != vertical.getValue()) {
361 if (horizontalOffset != horizontal.getValue()) {
373 public void setOrigin(
final int firstLine,
final int horizontalOffset) {
374 boolean changed =
false;
411 focusedComponent =
this;
413 }
catch (
final NullPointerException e) {
414 LOG.error(
"Null Pointer Exception in JEditTextArea.setEditingFocus()");
424 public void scrollTo(
final int line,
final int offset) {
430 if (visibleLines == 0) {
437 int newHorizontalOffset = horizontalOffset;
439 if (line < newFirstLine + electricScroll) {
440 newFirstLine = Math.max(0, line - electricScroll);
441 }
else if (line + electricScroll >= newFirstLine + visibleLines) {
442 newFirstLine = (line - visibleLines) + electricScroll + 1;
443 if (newFirstLine + visibleLines >= selection.
getLineCount()) {
446 if (newFirstLine < 0) {
451 final int x = painter.
offsetToX2(line, offset);
455 newHorizontalOffset = Math.min(0, horizontalOffset - x + width + 5);
456 }
else if (x + width >= painter.getWidth()) {
457 newHorizontalOffset = horizontalOffset + (painter.getWidth() - x) - width - 5;
460 setOrigin(newFirstLine, newHorizontalOffset);
477 public int offsetToX(
final int line,
final int offset) {
555 public void setText(@NotNull
final String text) {
566 public String
getText(
final int start,
final int len) {
567 return selection.
getText(start, len);
577 public void getText(
final int start,
final int len, @NotNull
final Segment segment) {
578 selection.
getText(start, len, segment);
654 public void select(
final int start,
final int end) {
657 final boolean newBias;
669 throw new IllegalArgumentException(
"Bounds out of range: " + newStart +
", " + newEnd);
681 if (oldBracketLine != -1) {
686 if (newBracketLine != -1) {
695 selection.
setSelection(newStart, newEnd, newStartLine, newEndLine, newBias);
701 CARET_TIMER.restart();
724 throw new InternalError(
"Text component read only");
774 if (caretLineEnd - caret <= str.length()) {
782 document.remove(caret, str.length());
783 document.insertString(caret, str, null);
784 }
catch (
final BadLocationException bl) {
785 bl.printStackTrace();
841 final Clipboard clipboard = getToolkit().getSystemClipboard();
846 final StringBuilder buf =
new StringBuilder();
847 for (
int i = 0; i < repeatCount; i++) {
848 buf.append(selection);
851 clipboard.setContents(
new StringSelection(buf.toString()), null);
860 final Clipboard clipboard = getToolkit().getSystemClipboard();
864 final String selection = ((String) clipboard.getContents(
this).getTransferData(DataFlavor.stringFlavor)).replace(
'\r',
'\n');
867 final StringBuilder buf =
new StringBuilder();
868 for (
int i = 0; i < repeatCount; i++) {
869 buf.append(selection);
872 }
catch (
final IOException e) {
874 LOG.error(
"Clipboard does not contain a string");
875 }
catch (
final UnsupportedFlavorException e) {
877 LOG.error(
"Clipboard does not contain a string");
888 super.removeNotify();
889 if (focusedComponent ==
this) {
890 focusedComponent = null;
901 case KeyEvent.KEY_TYPED:
902 inputHandler.keyTyped(e);
905 case KeyEvent.KEY_PRESSED:
906 inputHandler.keyPressed(e);
909 case KeyEvent.KEY_RELEASED:
910 inputHandler.keyReleased(e);
914 super.processKeyEvent(e);
918 if (newCaretPosition == 0) {
928 brackets.
set(bracketPosition, bracketLine);
931 }
catch (
final BadLocationException bl) {
932 bl.printStackTrace();
939 final DocumentEvent.ElementChange ch = evt.getChange(document.getDefaultRootElement());
945 count = ch.getChildrenAdded().length - ch.getChildrenRemoved().length;
953 if (line < firstLine) {
971 return !unmodifiedText.equals(selection.
getText());
978 unmodifiedText = selection.
getText();
985 if (focusedComponent != null && focusedComponent.hasFocus()) {
996 if (!scrollBarsInitialized) {
1003 SwingUtilities.invokeLater(
new Runnable() {
1007 if (e.getAdjustable() ==
vertical) {
1024 scrollBarsInitialized =
true;
1035 final int offset = e.getOffset();
1036 final int length = e.getLength();
1041 if (selectionStart > offset || (selectionStart == selectionEnd && selectionStart == offset)) {
1042 newStart = selectionStart + length;
1044 newStart = selectionStart;
1048 if (selectionEnd >= offset) {
1049 newEnd = selectionEnd + length;
1051 newEnd = selectionEnd;
1054 select(newStart, newEnd);
1061 final int offset = e.getOffset();
1062 final int length = e.getLength();
1067 if (selectionStart > offset) {
1068 if (selectionStart > offset + length) {
1069 newStart = selectionStart - length;
1074 newStart = selectionStart;
1078 if (selectionEnd > offset) {
1079 if (selectionEnd > offset + length) {
1080 newEnd = selectionEnd - length;
1085 newEnd = selectionEnd;
1088 select(newStart, newEnd);
1101 if (popup != null && popup.isVisible()) {
1126 focusedComponent = null;
1144 if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 && popup != null) {
1145 popup.show(painter, e.getX(), e.getY());
1149 final int line = painter.
yToLine(e.getY());
1150 final int offset =
xToOffset(line, e.getX());
1153 switch (e.getClickCount()) {
1155 doSingleClick(e, dot);
1158 doDoubleClick(line, offset, dot);
1161 doTripleClick(line);
1169 if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
1170 diff = e.getUnitsToScroll() * vertical.getUnitIncrement(1);
1172 diff = e.getWheelRotation() * vertical.getBlockIncrement();
1174 vertical.setValue(vertical.getValue() + diff);
1178 if ((evt.getModifiers() & InputEvent.SHIFT_MASK) == 0) {
1194 if (bracket != -1) {
1197 if (bracket > mark) {
1204 }
catch (
final BadLocationException bl) {
1205 bl.printStackTrace();
1209 final CharSequence lineText = selection.
getLineText(line);
1210 char ch = lineText.charAt(Math.max(0, offset - 1));
1212 String noWordSep = (String) document.getProperty(
"noWordSep");
1213 if (noWordSep == null) {
1219 final boolean selectNoLetter = !Character.isLetterOrDigit(ch) && noWordSep.indexOf(ch) == -1;
1223 for (
int i = offset - 1; i >= 0; i--) {
1224 ch = lineText.charAt(i);
1225 if (selectNoLetter ^ (!Character.isLetterOrDigit(ch) && noWordSep.indexOf(ch) == -1)) {
1231 int wordEnd = lineText.length();
1232 for (
int i = offset; i < lineText.length(); i++) {
1233 ch = lineText.charAt(i);
1234 if (selectNoLetter ^ (!Character.isLetterOrDigit(ch) && noWordSep.indexOf(ch) == -1)) {
1241 select(lineStart + wordStart, lineStart + wordEnd);
1265 private static final long serialVersionUID = 1L;
1284 return "caret move";
1288 public void undo() throws CannotUndoException {
1295 public void redo() throws CannotRedoException {
1302 public boolean addEdit(@NotNull
final UndoableEdit anEdit) {
1304 final CaretUndo caretUndo = (CaretUndo) anEdit;
1305 start = caretUndo.
start;
1306 end = caretUndo.
end;
void invalidateSelectedLines()
Repaints the lines containing the selection.
int getCaretLine()
Returns the caret line.
void setSelectedText(@NotNull final String selectedText)
Replaces the selection with the specified text.
void setCaretVisible(final boolean caretVisible)
Sets if the caret should be visible.
boolean isModified()
Return whether the text content has been modified from the "unmodified" state.
int getFirstLine()
Returns the line displayed at the text area's origin.
String getPresentationName()
void clear()
Clears the highlighted bracket.
void setSelectionRectangular(final boolean rectangleSelect)
Sets if the selection should be rectangular.
A document implementation that can be tokenized by the syntax highlighting system.
int lineToY(final int line)
Converts a line index to a y co-ordinate.
final void setFont(@NotNull final Font font)
void setEditingFocus()
Sets the focus to this TextArea, so this component is instantly registered for key press events...
int getMarkPosition()
Returns the mark position.
int getSelectionEnd()
Returns the selection end offset.
static final String BOTTOM
boolean isOverwrite()
Returns whether overwrite mode is active.
int offsetToX(final int line, final int offset)
Converts an offset in a line into an x co-ordinate.
int getCaretPosition()
Returns the caret position.
void changedUpdate(@NotNull final DocumentEvent e)
void processKeyEvent(@NotNull final KeyEvent e)
Forwards key events directly to the input handler.
int getSelectionStart()
Returns the selection start offset.
int getSelectionStart()
Returns the selection start offset.
final JScrollBar horizontal
final JScrollBar vertical
void setHorizontalOffset(final int horizontalOffset)
Sets the horizontal offset of drawn lines.
FontMetrics getFontMetrics()
Returns the font metrics used by this component.
final TextAreaPainter painter
The text area repaint manager.
void recalculateVisibleLines()
Recalculates the number of visible lines.
void updateScrollBars()
Updates the state of the scroll bars.
int getSelectionEnd()
Returns the selection end offset.
static final long serialVersionUID
Serial Version UID.
void actionPerformed(@NotNull final ActionEvent e)
void blinkCaret()
Blinks the caret.
static int findMatchingBracket(final Document doc, final int offset)
Returns the offset of the bracket matching the one at the specified offset of the document...
int getLineCount()
Returns the number of lines in the document.
void setText(@NotNull final String text)
Sets the entire text of this text area.
int getDocumentLength()
Returns the length of the document.
int getLineLength(final int line)
Returns the length of the specified line.
int getHorizontalOffset()
Returns the horizontal offset of drawn lines.
void setOrigin(final int firstLine, final int horizontalOffset)
A fast way of changing both the first line and horizontal offset.
void paste()
Inserts the clipboard contents into the text.
boolean isBracketHighlightEnabled()
Returns whether bracket highlighting is enabled.
void mouseDragged(@NotNull final MouseEvent e)
static JEditTextArea focusedComponent
boolean setHorizontalOffset(final int horizontalOffset)
An input handler converts the user's key strokes into concrete actions.
String getText(final int start, final int len)
Returns the specified substring of the document.
int xyToOffset(final int x, final int y)
Converts a point to an offset, from the start of the text.
int getDefaultCharWidth()
This works only for fonts with fixed line height.
void disableSelectionIfEmpty()
void setOverwrite(final boolean overwrite)
Sets whether overwrite mode is active.
CharSequence getLineText(final int lineIndex)
Returns the text on the specified line.
boolean scrollBarsInitialized
JEditTextArea(@NotNull final TextAreaDefaults defaults, @NotNull final SyntaxDocument document, final boolean paintInvalid)
Creates a new JEditTextArea with the specified settings.
void focusLost(@NotNull final FocusEvent e)
void insertUpdate(@NotNull final DocumentEvent e)
int xToOffset(final int line, final int x)
Converts an x co-ordinate to an offset within a line.
int getLineCount()
Returns the number of lines in the document.
final TextAreaSelection selection
InputHandler getInputHandler()
Returns the input handler.
boolean addEdit(@NotNull final UndoableEdit anEdit)
void updateBracketHighlight(final int newCaretPosition)
void setSelection(final int newStart, final int newEnd, final int newStartLine, final int newEndLine, final boolean newBias)
void selectAll()
Selects all text in the document.
SyntaxDocument getDocument()
Returns the document this text area is editing.
boolean isEditable()
Returns true if this text area is editable, false otherwise.
int offsetToX2(final int line, final int offset)
Converts an offset in a line into an x co-ordinate.
static void beginCompoundEdit()
Starts a compound edit that can be undone in one operation.
static final Timer CARET_TIMER
int yToLine(final int y)
Converts a y co-ordinate to a line index.
void setText(@NotNull final String text)
Sets the entire text of this text area.
static final Category LOG
The Logger for printing log messages.
int getMarkPosition()
Returns the mark position.
void setFont(@NotNull final Font font)
Set the TextArea font.
int getLineStartOffset(final int line)
Returns the start offset of the specified line.
int getSelectionStartLine()
Returns the selection start line.
void select(final int start, final int end)
Selects from the start offset to the end offset.
String getSelectedText()
Returns the selected text, or null if no selection is active.
void scrollToCaret()
Ensures that the caret is visible by scrolling the text area if necessary.
CaretUndo(final int start, final int end)
void invalidateLineRange(final int firstLine, final int lastLine)
Marks a range of lines as needing a repaint.
boolean isSelectionRectangular()
Returns true if the selection is rectangular, false otherwise.
int getCaretPosition()
Returns the caret position.
void setMagicCaretPosition(final int magicCaret)
Sets the `magic' caret position.
final TextAreaCaret caret
CharSequence getLineText(final int lineIndex)
Returns the text on the specified line.
static void endCompoundEdit()
Ends a compound edit that can be undone in one operation.
void setSelectionRectangular(final boolean rectangleSelect)
Sets if the selection should be rectangular.
final TextAreaConfig config
The TextAreaConfig for this instance.
void doSingleClick(@NotNull final InputEvent evt, final int dot)
final TextAreaBrackets brackets
String getText(final int start, final int len)
Returns the specified substring of the document.
int getElectricScroll()
Returns the number of lines from the top and button of the text area that are always visible...
boolean setFirstLine(final int firstLine)
int getFirstLine()
Returns the line displayed at the text area's origin.
Document getDocument()
Returns the document this text area is editing.
String getText()
Returns the entire text of this text area.
void resetModified()
Reset the "modified" state.
int offsetToX(final int line, final int offset)
Converts an offset in a line into an x co-ordinate.
void mouseWheelMoved(@NotNull final MouseWheelEvent e)
void doDoubleClick(final int line, final int offset, final int dot)
int getCaretLine()
Returns the caret line.
static final String CENTER
void removeNotify()
Called by the AWT when this component is removed from it's parent.
boolean blinkCaret()
Blinks the caret.
void removeUpdate(@NotNull final DocumentEvent e)
void setMagicCaret(final int magicCaret)
int getLineEndOffset(final int line)
Returns the end offset of the specified line.
int getMagicCaretPosition()
Returns the `magic' caret position.
int lineToY(final int line)
Converts a line index to a y co-ordinate.
int getRepeatCount()
Returns the number of times the next action will be repeated.
void doTripleClick(final int line)
void copy()
Places the selected text into the clipboard.
void overwriteSetSelectedText(@NotNull final String str)
Similar to.
void mouseMoved(@NotNull final MouseEvent e)
void documentChanged(@NotNull final DocumentEvent evt)
Maintains information about the highlighted pairs of brackets.
boolean isSelectionRectangular()
Returns true if the selection is rectangular, false otherwise.
void focusGained(@NotNull final FocusEvent e)
boolean isOverwriteEnabled()
Returns whether overwrite mode is active.
void setFirstLine(final int firstLine)
Sets the line displayed at the text area's origin without updating the scroll bars.
void cut()
Deletes the selected text from the text area and places it into the clipboard.
void setCaretPosition(final int caret)
Sets the caret position.
int xToOffset(final int line, final int x)
Converts an x co-ordinate to an offset within a line.
static final String RIGHT
void setCaretVisible(final boolean caretVisible)
Sets if the caret should be visible.
String unmodifiedText
The text contents in the last "unmodified" state.
void getText(final int start, final int len, @NotNull final Segment segment)
Copies the specified substring of the document into a segment.
int getLineStartOffset(final int line)
Returns the start offset of the specified line.
int getLineEndOffset(final int line)
Returns the end offset of the specified line.
void componentResized(@NotNull final ComponentEvent e)
void setBlink(final boolean blink)
void freeTabKeyFromFocusTraversal()
In JDKs above 1.4, the tab key is used for focus traversal.
final InputHandler inputHandler
final SyntaxDocument document
int getVisibleLines()
Returns the number of lines visible in this text area.
static void addUndoableEdit(@NotNull final UndoableEdit edit)
Adds an undoable edit to this document's undo list.
jEdit's text area component.
void adjustmentValueChanged(@NotNull final AdjustmentEvent e)
void setOverwriteEnabled(final boolean overwrite)
Sets whether overwrite mode is active.
Miscellaneous configuration settings for JEditTextArea.
Class with several utility functions used by the text area component.
int getBracketLine()
Returns the line of the highlighted bracket (the bracket matching the one before the caret)...
int getSelectionEndLine()
Returns the selection end line.
int getLineOfOffset(final int offset)
Returns the line containing the specified offset.
void mousePressed(@NotNull final MouseEvent e)
void scrollTo(final int line, final int offset)
Ensures that the specified line and offset is visible by scrolling the text area if necessary...
void set(final int bracketPosition, final int bracketLine)
Sets the highlighted bracket.
int getDocumentLength()
Returns the length of the document.
String getSelectedText()
Returns the selected text, or null if no selection is active.
int offsetToX2(final int line, final int offset)
Converts an offset in a line into an x co-ordinate.
Encapsulates default settings for a text area.
void setSelectedText(@NotNull final String selectedText)
Replaces the selection with the specified text.
void invalidateLine(final int line)
Marks a line as needing a repaint.