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.DocumentEvent.ElementChange;
48 import javax.swing.event.DocumentListener;
49 import javax.swing.text.BadLocationException;
50 import javax.swing.text.Document;
51 import javax.swing.text.Segment;
52 import javax.swing.undo.AbstractUndoableEdit;
53 import javax.swing.undo.CannotRedoException;
54 import javax.swing.undo.CannotUndoException;
55 import javax.swing.undo.UndoableEdit;
56 import org.apache.log4j.Category;
57 import org.apache.log4j.Logger;
58 import org.jetbrains.annotations.NotNull;
59 import org.jetbrains.annotations.Nullable;
130 private final JScrollBar
vertical =
new JScrollBar(Adjustable.VERTICAL);
133 private final JScrollBar
horizontal =
new JScrollBar(Adjustable.HORIZONTAL);
163 enableEvents(AWTEvent.KEY_EVENT_MASK);
183 painter.addMouseListener(mouseHandler);
184 painter.addMouseWheelListener(mouseHandler);
195 popup = defaults.getPopup();
232 final Set<KeyStroke> forwardTraversalKeys =
new HashSet<>();
233 forwardTraversalKeys.add(KeyStroke.getKeyStroke(
"control TAB"));
236 final Field field = Class.forName(
"java.awt.KeyboardFocusManager").getField(
"FORWARD_TRAVERSAL_KEYS");
237 final Integer value = field.getInt(field);
239 for (
final Method method : getClass().getMethods()) {
241 if (method.getName().equalsIgnoreCase(
"setFocusTraversalKeys")) {
242 method.invoke(
this, value, forwardTraversalKeys);
246 }
catch (
final ClassNotFoundException | IllegalAccessException | InvocationTargetException | NoSuchFieldException ignored) {
256 public void setFont(@NotNull
final Font font) {
301 if (visibleLines != 0) {
305 vertical.setBlockIncrement(visibleLines);
308 final int width =
painter.getWidth();
333 if (firstLine !=
vertical.getValue()) {
356 if (horizontalOffset !=
horizontal.getValue()) {
368 private void setOrigin(
final int firstLine,
final int horizontalOffset) {
369 boolean changed =
false;
408 }
catch (
final NullPointerException e) {
409 LOG.error(
"Null Pointer Exception in JEditTextArea.setEditingFocus()");
419 private void scrollTo(
final int line,
final int offset) {
425 if (visibleLines == 0) {
433 if (line < newFirstLine + electricScroll) {
434 newFirstLine = Math.max(0, line - electricScroll);
435 }
else if (line + electricScroll >= newFirstLine + visibleLines) {
436 newFirstLine = (line - visibleLines) + electricScroll + 1;
440 if (newFirstLine < 0) {
448 int newHorizontalOffset = horizontalOffset;
450 newHorizontalOffset = Math.min(0, horizontalOffset - x + width + 5);
451 }
else if (x + width >=
painter.getWidth()) {
452 newHorizontalOffset = horizontalOffset + (
painter.getWidth() - x) - width - 5;
455 setOrigin(newFirstLine, newHorizontalOffset);
472 public int offsetToX(
final int line,
final int offset) {
550 public void setText(@NotNull
final String text) {
561 public String
getText(
final int start,
final int len) {
572 public void getText(
final int start,
final int len, @NotNull
final Segment segment) {
649 public void select(
final int start,
final int end) {
652 final boolean newBias;
664 throw new IllegalArgumentException(
"Bounds out of range: " + newStart +
", " + newEnd);
676 if (oldBracketLine != -1) {
681 if (newBracketLine != -1) {
719 throw new InternalError(
"Text component read only");
769 if (caretLineEnd -
caret <= str.length()) {
779 }
catch (
final BadLocationException bl) {
780 bl.printStackTrace();
836 final Clipboard clipboard = getToolkit().getSystemClipboard();
841 final StringBuilder buf =
new StringBuilder();
842 for (
int i = 0; i < repeatCount; i++) {
846 clipboard.setContents(
new StringSelection(buf.toString()),
null);
855 final Clipboard clipboard = getToolkit().getSystemClipboard();
859 final String
selection = ((String) clipboard.getContents(
this).getTransferData(DataFlavor.stringFlavor)).replace(
'\r',
'\n');
862 final StringBuilder buf =
new StringBuilder();
863 for (
int i = 0; i < repeatCount; i++) {
867 }
catch (
final IOException | UnsupportedFlavorException e) {
869 LOG.error(
"Clipboard does not contain a string");
880 super.removeNotify();
893 case KeyEvent.KEY_TYPED:
897 case KeyEvent.KEY_PRESSED:
901 case KeyEvent.KEY_RELEASED:
906 super.processKeyEvent(e);
910 if (newCaretPosition == 0) {
923 }
catch (
final BadLocationException bl) {
924 bl.printStackTrace();
931 final ElementChange ch = evt.getChange(
document.getDefaultRootElement());
932 final int count = ch ==
null ? 0 : ch.getChildrenAdded().length - ch.getChildrenRemoved().length;
938 if (line < firstLine) {
988 SwingUtilities.invokeLater(() -> {
989 if (e.getAdjustable() ==
vertical) {
990 setFirstLine(vertical.getValue());
992 setHorizontalOffset(-horizontal.getValue());
1015 final int offset = e.getOffset();
1016 final int length = e.getLength();
1021 if (selectionStart > offset || (selectionStart == selectionEnd && selectionStart == offset)) {
1022 newStart = selectionStart + length;
1024 newStart = selectionStart;
1028 if (selectionEnd >= offset) {
1029 newEnd = selectionEnd + length;
1031 newEnd = selectionEnd;
1034 select(newStart, newEnd);
1041 final int offset = e.getOffset();
1042 final int length = e.getLength();
1047 if (selectionStart > offset) {
1048 if (selectionStart > offset + length) {
1049 newStart = selectionStart - length;
1054 newStart = selectionStart;
1058 if (selectionEnd > offset) {
1059 if (selectionEnd > offset + length) {
1060 newEnd = selectionEnd - length;
1065 newEnd = selectionEnd;
1068 select(newStart, newEnd);
1124 if ((e.getModifiers() & InputEvent.BUTTON3_MASK) != 0 &&
popup !=
null) {
1130 final int offset =
xToOffset(line, e.getX());
1133 switch (e.getClickCount()) {
1149 if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
1150 diff = e.getUnitsToScroll() *
vertical.getUnitIncrement(1);
1152 diff = e.getWheelRotation() *
vertical.getBlockIncrement();
1158 if ((evt.getModifiers() & InputEvent.SHIFT_MASK) == 0) {
1174 if (bracket != -1) {
1177 if (bracket > mark) {
1184 }
catch (
final BadLocationException bl) {
1185 bl.printStackTrace();
1190 char ch = lineText.charAt(Math.max(0, offset - 1));
1192 String noWordSep = (String)
document.getProperty(
"noWordSep");
1193 if (noWordSep ==
null) {
1199 final boolean selectNoLetter = !Character.isLetterOrDigit(ch) && noWordSep.indexOf(ch) == -1;
1203 for (
int i = offset - 1; i >= 0; i--) {
1204 ch = lineText.charAt(i);
1205 if (selectNoLetter ^ (!Character.isLetterOrDigit(ch) && noWordSep.indexOf(ch) == -1)) {
1211 int wordEnd = lineText.length();
1212 for (
int i = offset; i < lineText.length(); i++) {
1213 ch = lineText.charAt(i);
1214 if (selectNoLetter ^ (!Character.isLetterOrDigit(ch) && noWordSep.indexOf(ch) == -1)) {
1221 select(lineStart + wordStart, lineStart + wordEnd);
1264 return "caret move";
1268 public void undo() throws CannotUndoException {
1275 public void redo() throws CannotRedoException {
1282 public boolean addEdit(@NotNull
final UndoableEdit anEdit) {