1 7 package javax.swing.text; 8 9 import java.awt.*; 10 import java.awt.event.*; 11 import java.awt.datatransfer.*; 12 import java.beans.*; 13 import java.awt.event.ActionEvent ; 14 import java.awt.event.ActionListener ; 15 import java.io.*; 16 import javax.swing.*; 17 import javax.swing.event.*; 18 import javax.swing.plaf.*; 19 import java.util.EventListener ; 20 import com.sun.java.swing.SwingUtilities2; 21 22 91 public class DefaultCaret extends Rectangle implements Caret , FocusListener, MouseListener, MouseMotionListener { 92 93 100 public static final int UPDATE_WHEN_ON_EDT = 0; 101 102 113 public static final int NEVER_UPDATE = 1; 114 115 125 public static final int ALWAYS_UPDATE = 2; 126 127 130 public DefaultCaret() { 131 } 132 133 185 public void setUpdatePolicy(int policy) { 186 updatePolicy = policy; 187 } 188 189 202 public int getUpdatePolicy() { 203 return updatePolicy; 204 } 205 206 212 protected final JTextComponent getComponent() { 213 return component; 214 } 215 216 226 protected final synchronized void repaint() { 227 if (component != null) { 228 component.repaint(x, y, width, height); 229 } 230 } 231 232 242 protected synchronized void damage(Rectangle r) { 243 if (r != null) { 244 int damageWidth = getCaretWidth(r.height); 245 x = r.x - 4 - (damageWidth >> 1); 246 y = r.y; 247 width = 9 + damageWidth; 248 height = r.height; 249 repaint(); 250 } 251 } 252 253 263 protected void adjustVisibility(Rectangle nloc) { 264 if(component == null) { 265 return; 266 } 267 if (SwingUtilities.isEventDispatchThread()) { 268 component.scrollRectToVisible(nloc); 269 } else { 270 SwingUtilities.invokeLater(new SafeScroller(nloc)); 271 } 272 } 273 274 279 protected Highlighter.HighlightPainter getSelectionPainter() { 280 return DefaultHighlighter.DefaultPainter; 281 } 282 283 289 protected void positionCaret(MouseEvent e) { 290 Point pt = new Point(e.getX(), e.getY()); 291 Position.Bias [] biasRet = new Position.Bias [1]; 292 int pos = component.getUI().viewToModel(component, pt, biasRet); 293 if(biasRet[0] == null) 294 biasRet[0] = Position.Bias.Forward; 295 if (pos >= 0) { 296 setDot(pos, biasRet[0]); 297 } 298 } 299 300 308 protected void moveCaret(MouseEvent e) { 309 Point pt = new Point(e.getX(), e.getY()); 310 Position.Bias [] biasRet = new Position.Bias [1]; 311 int pos = component.getUI().viewToModel(component, pt, biasRet); 312 if(biasRet[0] == null) 313 biasRet[0] = Position.Bias.Forward; 314 if (pos >= 0) { 315 moveDot(pos, biasRet[0]); 316 } 317 } 318 319 321 329 public void focusGained(FocusEvent e) { 330 if (component.isEnabled()) { 331 if (component.isEditable()) { 332 setVisible(true); 333 } 334 setSelectionVisible(true); 335 } 336 } 337 338 346 public void focusLost(FocusEvent e) { 347 setVisible(false); 348 setSelectionVisible(ownsSelection || e.isTemporary()); 349 } 350 351 352 355 private void selectWord(MouseEvent e) { 356 if (selectedWordEvent != null 357 && selectedWordEvent.getX() == e.getX() 358 && selectedWordEvent.getY() == e.getY()) { 359 return; 361 } 362 Action a = null; 363 ActionMap map = getComponent().getActionMap(); 364 if (map != null) { 365 a = map.get(DefaultEditorKit.selectWordAction); 366 } 367 if (a == null) { 368 if (selectWord == null) { 369 selectWord = new DefaultEditorKit.SelectWordAction (); 370 } 371 a = selectWord; 372 } 373 a.actionPerformed(new ActionEvent (getComponent(), 374 ActionEvent.ACTION_PERFORMED, null, e.getWhen(), e.getModifiers())); 375 selectedWordEvent = e; 376 } 377 378 380 388 public void mouseClicked(MouseEvent e) { 389 int nclicks = SwingUtilities2.getAdjustedClickCount(getComponent(), e); 390 391 if (! e.isConsumed()) { 392 if (SwingUtilities.isLeftMouseButton(e)) { 393 if(nclicks == 1) { 395 selectedWordEvent = null; 396 } else if(nclicks == 2 397 && SwingUtilities2.canEventAccessSystemClipboard(e)) { 398 selectWord(e); 399 selectedWordEvent = null; 400 } else if(nclicks == 3 401 && SwingUtilities2.canEventAccessSystemClipboard(e)) { 402 Action a = null; 403 ActionMap map = getComponent().getActionMap(); 404 if (map != null) { 405 a = map.get(DefaultEditorKit.selectLineAction); 406 } 407 if (a == null) { 408 if (selectLine == null) { 409 selectLine = new DefaultEditorKit.SelectLineAction (); 410 } 411 a = selectLine; 412 } 413 a.actionPerformed(new ActionEvent (getComponent(), 414 ActionEvent.ACTION_PERFORMED, null, e.getWhen(), e.getModifiers())); 415 } 416 } else if (SwingUtilities.isMiddleMouseButton(e)) { 417 if (nclicks == 1 && component.isEditable() && component.isEnabled() 419 && SwingUtilities2.canEventAccessSystemClipboard(e)) { 420 JTextComponent c = (JTextComponent ) e.getSource(); 422 if (c != null) { 423 try { 424 Toolkit tk = c.getToolkit(); 425 Clipboard buffer = tk.getSystemSelection(); 426 if (buffer != null) { 427 adjustCaret(e); 429 TransferHandler th = c.getTransferHandler(); 430 if (th != null) { 431 Transferable trans = null; 432 433 try { 434 trans = buffer.getContents(null); 435 } catch (IllegalStateException ise) { 436 UIManager.getLookAndFeel().provideErrorFeedback(c); 438 } 439 440 if (trans != null) { 441 th.importData(c, trans); 442 } 443 } 444 adjustFocus(true); 445 } 446 } catch (HeadlessException he) { 447 } 449 } 450 } 451 } 452 } 453 } 454 455 467 public void mousePressed(MouseEvent e) { 468 int nclicks = SwingUtilities2.getAdjustedClickCount(getComponent(), e); 469 470 if (SwingUtilities.isLeftMouseButton(e)) { 471 if (e.isConsumed()) { 472 shouldHandleRelease = true; 473 } else { 474 shouldHandleRelease = false; 475 adjustCaretAndFocus(e); 476 if (nclicks == 2 477 && SwingUtilities2.canEventAccessSystemClipboard(e)) { 478 selectWord(e); 479 } 480 } 481 } 482 } 483 484 void adjustCaretAndFocus(MouseEvent e) { 485 adjustCaret(e); 486 adjustFocus(false); 487 } 488 489 492 private void adjustCaret(MouseEvent e) { 493 if ((e.getModifiers() & ActionEvent.SHIFT_MASK) != 0 && 494 getDot() != -1) { 495 moveCaret(e); 496 } else { 497 positionCaret(e); 498 } 499 } 500 501 506 private void adjustFocus(boolean inWindow) { 507 if ((component != null) && component.isEnabled() && 508 component.isRequestFocusEnabled()) { 509 if (inWindow) { 510 component.requestFocusInWindow(); 511 } 512 else { 513 component.requestFocus(); 514 } 515 } 516 } 517 518 524 public void mouseReleased(MouseEvent e) { 525 if (!e.isConsumed() 526 && shouldHandleRelease 527 && SwingUtilities.isLeftMouseButton(e)) { 528 529 adjustCaretAndFocus(e); 530 } 531 } 532 533 539 public void mouseEntered(MouseEvent e) { 540 } 541 542 548 public void mouseExited(MouseEvent e) { 549 } 550 551 553 563 public void mouseDragged(MouseEvent e) { 564 if ((! e.isConsumed()) && SwingUtilities.isLeftMouseButton(e)) { 565 moveCaret(e); 566 } 567 } 568 569 575 public void mouseMoved(MouseEvent e) { 576 } 577 578 580 596 public void paint(Graphics g) { 597 if(isVisible()) { 598 try { 599 TextUI mapper = component.getUI(); 600 Rectangle r = mapper.modelToView(component, dot, dotBias); 601 602 if ((r == null) || ((r.width == 0) && (r.height == 0))) { 603 return; 604 } 605 if (width > 0 && height > 0 && 606 !this._contains(r.x, r.y, r.width, r.height)) { 607 Rectangle clip = g.getClipBounds(); 610 611 if (clip != null && !clip.contains(this)) { 612 repaint(); 615 } 616 damage(r); 620 } 621 g.setColor(component.getCaretColor()); 622 int paintWidth = getCaretWidth(r.height); 623 r.x -= paintWidth >> 1; 624 g.fillRect(r.x, r.y, paintWidth , r.height - 1); 625 626 Document doc = component.getDocument(); 632 if (doc instanceof AbstractDocument ) { 633 Element bidi = ((AbstractDocument )doc).getBidiRootElement(); 634 if ((bidi != null) && (bidi.getElementCount() > 1)) { 635 flagXPoints[0] = r.x + ((dotLTR) ? paintWidth : 0); 637 flagYPoints[0] = r.y; 638 flagXPoints[1] = flagXPoints[0]; 639 flagYPoints[1] = flagYPoints[0] + 4; 640 flagXPoints[2] = flagXPoints[0] + ((dotLTR) ? 4 : -4); 641 flagYPoints[2] = flagYPoints[0]; 642 g.fillPolygon(flagXPoints, flagYPoints, 3); 643 } 644 } 645 } catch (BadLocationException e) { 646 } 649 } 650 } 651 652 663 public void install(JTextComponent c) { 664 component = c; 665 Document doc = c.getDocument(); 666 dot = mark = 0; 667 dotLTR = markLTR = true; 668 dotBias = markBias = Position.Bias.Forward; 669 if (doc != null) { 670 doc.addDocumentListener(handler); 671 } 672 c.addPropertyChangeListener(handler); 673 c.addFocusListener(this); 674 c.addMouseListener(this); 675 c.addMouseMotionListener(this); 676 677 if (component.hasFocus()) { 680 focusGained(null); 681 } 682 683 Number ratio = (Number ) c.getClientProperty("caretAspectRatio"); 684 if (ratio != null) { 685 aspectRatio = ratio.floatValue(); 686 } else { 687 aspectRatio = -1; 688 } 689 690 Integer width = (Integer ) c.getClientProperty("caretWidth"); 691 if (width != null) { 692 caretWidth = width.intValue(); 693 } else { 694 caretWidth = -1; 695 } 696 } 697 698 706 public void deinstall(JTextComponent c) { 707 c.removeMouseListener(this); 708 c.removeMouseMotionListener(this); 709 c.removeFocusListener(this); 710 c.removePropertyChangeListener(handler); 711 Document doc = c.getDocument(); 712 if (doc != null) { 713 doc.removeDocumentListener(handler); 714 } 715 synchronized(this) { 716 component = null; 717 } 718 if (flasher != null) { 719 flasher.stop(); 720 } 721 722 723 } 724 725 732 public void addChangeListener(ChangeListener l) { 733 listenerList.add(ChangeListener.class, l); 734 } 735 736 742 public void removeChangeListener(ChangeListener l) { 743 listenerList.remove(ChangeListener.class, l); 744 } 745 746 759 public ChangeListener[] getChangeListeners() { 760 return (ChangeListener[])listenerList.getListeners( 761 ChangeListener.class); 762 } 763 764 772 protected void fireStateChanged() { 773 Object [] listeners = listenerList.getListenerList(); 775 for (int i = listeners.length-2; i>=0; i-=2) { 778 if (listeners[i]==ChangeListener.class) { 779 if (changeEvent == null) 781 changeEvent = new ChangeEvent(this); 782 ((ChangeListener)listeners[i+1]).stateChanged(changeEvent); 783 } 784 } 785 } 786 787 823 public <T extends EventListener > T[] getListeners(Class <T> listenerType) { 824 return listenerList.getListeners(listenerType); 825 } 826 827 832 public void setSelectionVisible(boolean vis) { 833 if (vis != selectionVisible) { 834 selectionVisible = vis; 835 if (selectionVisible) { 836 Highlighter h = component.getHighlighter(); 838 if ((dot != mark) && (h != null) && (selectionTag == null)) { 839 int p0 = Math.min(dot, mark); 840 int p1 = Math.max(dot, mark); 841 Highlighter.HighlightPainter p = getSelectionPainter(); 842 try { 843 selectionTag = h.addHighlight(p0, p1, p); 844 } catch (BadLocationException bl) { 845 selectionTag = null; 846 } 847 } 848 } else { 849 if (selectionTag != null) { 851 Highlighter h = component.getHighlighter(); 852 h.removeHighlight(selectionTag); 853 selectionTag = null; 854 } 855 } 856 } 857 } 858 859 864 public boolean isSelectionVisible() { 865 return selectionVisible; 866 } 867 868 882 public boolean isActive() { 883 return active; 884 } 885 886 903 public boolean isVisible() { 904 return visible; 905 } 906 907 941 public void setVisible(boolean e) { 942 if (component != null) { 946 active = e; 947 TextUI mapper = component.getUI(); 948 if (visible != e) { 949 visible = e; 950 try { 952 Rectangle loc = mapper.modelToView(component, dot,dotBias); 953 damage(loc); 954 } catch (BadLocationException badloc) { 955 } 957 } 958 } 959 if (flasher != null) { 960 if (visible) { 961 flasher.start(); 962 } else { 963 flasher.stop(); 964 } 965 } 966 } 967 968 974 public void setBlinkRate(int rate) { 975 if (rate != 0) { 976 if (flasher == null) { 977 flasher = new Timer(rate, handler); 978 } 979 flasher.setDelay(rate); 980 } else { 981 if (flasher != null) { 982 flasher.stop(); 983 flasher.removeActionListener(handler); 984 flasher = null; 985 } 986 } 987 } 988 989 996 public int getBlinkRate() { 997 return (flasher == null) ? 0 : flasher.getDelay(); 998 } 999 1000 1006 public int getDot() { 1007 return dot; 1008 } 1009 1010 1017 public int getMark() { 1018 return mark; 1019 } 1020 1021 1028 public void setDot(int dot) { 1029 setDot(dot, Position.Bias.Forward); 1030 } 1031 1032 1038 public void moveDot(int dot) { 1039 moveDot(dot, Position.Bias.Forward); 1040 } 1041 1042 1044 void moveDot(int dot, Position.Bias dotBias) { 1045 if (! component.isEnabled()) { 1046 setDot(dot, dotBias); 1048 return; 1049 } 1050 if (dot != this.dot) { 1051 NavigationFilter filter = component.getNavigationFilter(); 1052 1053 if (filter != null) { 1054 filter.moveDot(getFilterBypass(), dot, dotBias); 1055 } 1056 else { 1057 handleMoveDot(dot, dotBias); 1058 } 1059 } 1060 } 1061 1062 void handleMoveDot(int dot, Position.Bias dotBias) { 1063 changeCaretPosition(dot, dotBias); 1064 1065 if (selectionVisible) { 1066 Highlighter h = component.getHighlighter(); 1067 if (h != null) { 1068 int p0 = Math.min(dot, mark); 1069 int p1 = Math.max(dot, mark); 1070 1071 if (p0 == p1) { 1073 if (selectionTag != null) { 1074 h.removeHighlight(selectionTag); 1075 selectionTag = null; 1076 } 1077 } else { 1079 try { 1080 if (selectionTag != null) { 1081 h.changeHighlight(selectionTag, p0, p1); 1082 } else { 1083 Highlighter.HighlightPainter p = getSelectionPainter(); 1084 selectionTag = h.addHighlight(p0, p1, p); 1085 } 1086 } catch (BadLocationException e) { 1087 throw new StateInvariantError ("Bad caret position"); 1088 } 1089 } 1090 } 1091 } 1092 } 1093 1094 void setDot(int dot, Position.Bias dotBias) { 1095 NavigationFilter filter = component.getNavigationFilter(); 1096 1097 if (filter != null) { 1098 filter.setDot(getFilterBypass(), dot, dotBias); 1099 } 1100 else { 1101 handleSetDot(dot, dotBias); 1102 } 1103 } 1104 1105 void handleSetDot(int dot, Position.Bias dotBias) { 1106 Document doc = component.getDocument(); 1108 if (doc != null) { 1109 dot = Math.min(dot, doc.getLength()); 1110 } 1111 dot = Math.max(dot, 0); 1112 1113 if( dot == 0 ) 1115 dotBias = Position.Bias.Forward; 1116 1117 mark = dot; 1118 if (this.dot != dot || this.dotBias != dotBias || 1119 selectionTag != null || forceCaretPositionChange) { 1120 changeCaretPosition(dot, dotBias); 1121 } 1122 this.markBias = this.dotBias; 1123 this.markLTR = dotLTR; 1124 Highlighter h = component.getHighlighter(); 1125 if ((h != null) && (selectionTag != null)) { 1126 h.removeHighlight(selectionTag); 1127 selectionTag = null; 1128 } 1129 } 1130 1131 Position.Bias getDotBias() { 1132 return dotBias; 1133 } 1134 1135 Position.Bias getMarkBias() { 1136 return markBias; 1137 } 1138 1139 boolean isDotLeftToRight() { 1140 return dotLTR; 1141 } 1142 1143 boolean isMarkLeftToRight() { 1144 return markLTR; 1145 } 1146 1147 boolean isPositionLTR(int position, Position.Bias bias) { 1148 Document doc = component.getDocument(); 1149 if(doc instanceof AbstractDocument ) { 1150 if(bias == Position.Bias.Backward && --position < 0) 1151 position = 0; 1152 return ((AbstractDocument )doc).isLeftToRight(position, position); 1153 } 1154 return true; 1155 } 1156 1157 Position.Bias guessBiasForOffset(int offset, Position.Bias lastBias, 1158 boolean lastLTR) { 1159 if(lastLTR != isPositionLTR(offset, lastBias)) { 1169 lastBias = Position.Bias.Backward; 1170 } 1171 else if(lastBias != Position.Bias.Backward && 1172 lastLTR != isPositionLTR(offset, Position.Bias.Backward)) { 1173 lastBias = Position.Bias.Backward; 1174 } 1175 if (lastBias == Position.Bias.Backward && offset > 0) { 1176 try { 1177 Segment s = new Segment (); 1178 component.getDocument().getText(offset - 1, 1, s); 1179 if (s.count > 0 && s.array[s.offset] == '\n') { 1180 lastBias = Position.Bias.Forward; 1181 } 1182 } 1183 catch (BadLocationException ble) {} 1184 } 1185 return lastBias; 1186 } 1187 1188 1190 1196 void changeCaretPosition(int dot, Position.Bias dotBias) { 1197 repaint(); 1200 1201 1202 if (flasher != null && flasher.isRunning()) { 1204 visible = true; 1205 flasher.restart(); 1206 } 1207 1208 this.dot = dot; 1210 this.dotBias = dotBias; 1211 dotLTR = isPositionLTR(dot, dotBias); 1212 fireStateChanged(); 1213 1214 updateSystemSelection(); 1215 1216 setMagicCaretPosition(null); 1217 1218 Runnable callRepaintNewCaret = new Runnable () { 1224 public void run() { 1225 repaintNewCaret(); 1226 } 1227 }; 1228 SwingUtilities.invokeLater(callRepaintNewCaret); 1229 } 1230 1231 1237 void repaintNewCaret() { 1238 if (component != null) { 1239 TextUI mapper = component.getUI(); 1240 Document doc = component.getDocument(); 1241 if ((mapper != null) && (doc != null)) { 1242 Rectangle newLoc; 1245 try { 1246 newLoc = mapper.modelToView(component, this.dot, this.dotBias); 1247 } catch (BadLocationException e) { 1248 newLoc = null; 1249 } 1250 if (newLoc != null) { 1251 adjustVisibility(newLoc); 1252 if (getMagicCaretPosition() == null) { 1254 setMagicCaretPosition(new Point(newLoc.x, newLoc.y)); 1255 } 1256 } 1257 1258 damage(newLoc); 1260 } 1261 } 1262 } 1263 1264 private void updateSystemSelection() { 1265 if ( ! SwingUtilities2.canCurrentEventAccessSystemClipboard() ) { 1266 return; 1267 } 1268 if (this.dot != this.mark && component != null) { 1269 Clipboard clip = getSystemSelection(); 1270 if (clip != null) { 1271 String selectedText = null; 1272 if (component instanceof JPasswordField 1273 && component.getClientProperty("JPasswordField.cutCopyAllowed") != 1274 Boolean.TRUE) { 1275 StringBuffer txt = null; 1277 char echoChar = ((JPasswordField)component).getEchoChar(); 1278 int p0 = Math.min(getDot(), getMark()); 1279 int p1 = Math.max(getDot(), getMark()); 1280 for (int i = p0; i < p1; i++) { 1281 if (txt == null) { 1282 txt = new StringBuffer (); 1283 } 1284 txt.append(echoChar); 1285 } 1286 selectedText = (txt != null) ? txt.toString() : null; 1287 } else { 1288 selectedText = component.getSelectedText(); 1289 } 1290 try { 1291 clip.setContents( 1292 new StringSelection(selectedText), getClipboardOwner()); 1293 1294 ownsSelection = true; 1295 } catch (IllegalStateException ise) { 1296 } 1300 } 1301 } 1302 } 1303 1304 private Clipboard getSystemSelection() { 1305 try { 1306 return component.getToolkit().getSystemSelection(); 1307 } catch (HeadlessException he) { 1308 } catch (SecurityException se) { 1310 } 1312 return null; 1313 } 1314 1315 private ClipboardOwner getClipboardOwner() { 1316 return handler; 1317 } 1318 1319 1325 private void ensureValidPosition() { 1326 int length = component.getDocument().getLength(); 1327 if (dot > length || mark > length) { 1328 handleSetDot(length, Position.Bias.Forward); 1332 } 1333 } 1334 1335 1336 1344 public void setMagicCaretPosition(Point p) { 1345 magicCaretPosition = p; 1346 } 1347 1348 1354 public Point getMagicCaretPosition() { 1355 return magicCaretPosition; 1356 } 1357 1358 1368 public boolean equals(Object obj) { 1369 return (this == obj); 1370 } 1371 1372 public String toString() { 1373 String s = "Dot=(" + dot + ", " + dotBias + ")"; 1374 s += " Mark=(" + mark + ", " + markBias + ")"; 1375 return s; 1376 } 1377 1378 private NavigationFilter.FilterBypass getFilterBypass() { 1379 if (filterBypass == null) { 1380 filterBypass = new DefaultFilterBypass(); 1381 } 1382 return filterBypass; 1383 } 1384 1385 private boolean _contains(int X, int Y, int W, int H) { 1388 int w = this.width; 1389 int h = this.height; 1390 if ((w | h | W | H) < 0) { 1391 return false; 1393 } 1394 int x = this.x; 1396 int y = this.y; 1397 if (X < x || Y < y) { 1398 return false; 1399 } 1400 if (W > 0) { 1401 w += x; 1402 W += X; 1403 if (W <= X) { 1404 if (w >= x || W > w) return false; 1409 } else { 1410 if (w >= x && W > w) return false; 1414 } 1415 } 1416 else if ((x + w) < X) { 1417 return false; 1418 } 1419 if (H > 0) { 1420 h += y; 1421 H += Y; 1422 if (H <= Y) { 1423 if (h >= y || H > h) return false; 1424 } else { 1425 if (h >= y && H > h) return false; 1426 } 1427 } 1428 else if ((y + h) < Y) { 1429 return false; 1430 } 1431 return true; 1432 } 1433 1434 int getCaretWidth(int height) { 1435 if (aspectRatio > -1) { 1436 return (int) (aspectRatio * height) + 1; 1437 } 1438 1439 if (caretWidth > -1) { 1440 return caretWidth; 1441 } 1442 1443 return 1; 1444 } 1445 1446 1448 private void readObject(ObjectInputStream s) 1449 throws ClassNotFoundException , IOException 1450 { 1451 s.defaultReadObject(); 1452 handler = new Handler(); 1453 if (!s.readBoolean()) { 1454 dotBias = Position.Bias.Forward; 1455 } 1456 else { 1457 dotBias = Position.Bias.Backward; 1458 } 1459 if (!s.readBoolean()) { 1460 markBias = Position.Bias.Forward; 1461 } 1462 else { 1463 markBias = Position.Bias.Backward; 1464 } 1465 } 1466 1467 private void writeObject(ObjectOutputStream s) throws IOException { 1468 s.defaultWriteObject(); 1469 s.writeBoolean((dotBias == Position.Bias.Backward)); 1470 s.writeBoolean((markBias == Position.Bias.Backward)); 1471 } 1472 1473 1475 1478 protected EventListenerList listenerList = new EventListenerList(); 1479 1480 1486 protected transient ChangeEvent changeEvent = null; 1487 1488 JTextComponent component; 1491 1492 int updatePolicy = UPDATE_WHEN_ON_EDT; 1493 boolean visible; 1494 boolean active; 1495 int dot; 1496 int mark; 1497 Object selectionTag; 1498 boolean selectionVisible; 1499 Timer flasher; 1500 Point magicCaretPosition; 1501 transient Position.Bias dotBias; 1502 transient Position.Bias markBias; 1503 boolean dotLTR; 1504 boolean markLTR; 1505 transient Handler handler = new Handler(); 1506 transient private int[] flagXPoints = new int[3]; 1507 transient private int[] flagYPoints = new int[3]; 1508 private transient NavigationFilter.FilterBypass filterBypass; 1509 static private transient Action selectWord = null; 1510 static private transient Action selectLine = null; 1511 1516 private boolean ownsSelection; 1517 1518 1524 private boolean forceCaretPositionChange; 1525 1526 1531 private transient boolean shouldHandleRelease; 1532 1533 1534 1537 private transient MouseEvent selectedWordEvent = null; 1538 1539 1542 private int caretWidth = -1; 1543 private float aspectRatio = -1; 1544 1545 class SafeScroller implements Runnable { 1546 1547 SafeScroller(Rectangle r) { 1548 this.r = r; 1549 } 1550 1551 public void run() { 1552 if (component != null) { 1553 component.scrollRectToVisible(r); 1554 } 1555 } 1556 1557 Rectangle r; 1558 } 1559 1560 1561 class Handler implements PropertyChangeListener, DocumentListener, ActionListener , ClipboardOwner { 1562 1563 1565 1572 public void actionPerformed(ActionEvent e) { 1573 if (width == 0 || height == 0) { 1574 if (component != null) { 1577 TextUI mapper = component.getUI(); 1578 try { 1579 Rectangle r = mapper.modelToView(component, dot, 1580 dotBias); 1581 if (r != null && r.width != 0 && r.height != 0) { 1582 damage(r); 1583 } 1584 } catch (BadLocationException ble) { 1585 } 1586 } 1587 } 1588 visible = !visible; 1589 repaint(); 1590 } 1591 1592 1594 1601 public void insertUpdate(DocumentEvent e) { 1602 if (getUpdatePolicy() == NEVER_UPDATE || 1603 (getUpdatePolicy() == UPDATE_WHEN_ON_EDT && 1604 !SwingUtilities.isEventDispatchThread())) { 1605 1606 if ((e.getOffset() <= dot || e.getOffset() <= mark) 1607 && selectionTag != null) { 1608 try { 1609 component.getHighlighter().changeHighlight(selectionTag, 1610 Math.min(dot, mark), Math.max(dot, mark)); 1611 } catch (BadLocationException e1) { 1612 e1.printStackTrace(); 1613 } 1614 } 1615 return; 1616 } 1617 int adjust = 0; 1618 int offset = e.getOffset(); 1619 int length = e.getLength(); 1620 int newDot = dot; 1621 short changed = 0; 1622 1623 if (e instanceof AbstractDocument.UndoRedoDocumentEvent ) { 1624 setDot(offset + length); 1625 return; 1626 } 1627 if (newDot >= offset) { 1628 newDot += length; 1629 changed |= 1; 1630 } 1631 int newMark = mark; 1632 if (newMark >= offset) { 1633 newMark += length; 1634 changed |= 2; 1635 } 1636 1637 if (changed != 0) { 1638 Position.Bias dotBias = DefaultCaret.this.dotBias; 1639 if (dot == offset) { 1640 Document doc = component.getDocument(); 1641 boolean isNewline; 1642 try { 1643 Segment s = new Segment (); 1644 doc.getText(newDot - 1, 1, s); 1645 isNewline = (s.count > 0 && 1646 s.array[s.offset] == '\n'); 1647 } catch (BadLocationException ble) { 1648 isNewline = false; 1649 } 1650 if (isNewline) { 1651 dotBias = Position.Bias.Forward; 1652 } else { 1653 dotBias = Position.Bias.Backward; 1654 } 1655 } 1656 if (newMark == newDot) { 1657 setDot(newDot, dotBias); 1658 ensureValidPosition(); 1659 } 1660 else { 1661 setDot(newMark, markBias); 1662 if (getDot() == newMark) { 1663 moveDot(newDot, dotBias); 1667 } 1668 ensureValidPosition(); 1669 } 1670 } 1671 } 1672 1673 1680 public void removeUpdate(DocumentEvent e) { 1681 if (getUpdatePolicy() == NEVER_UPDATE || 1682 (getUpdatePolicy() == UPDATE_WHEN_ON_EDT && 1683 !SwingUtilities.isEventDispatchThread())) { 1684 1685 int length = component.getDocument().getLength(); 1686 dot = Math.min(dot, length); 1687 mark = Math.min(mark, length); 1688 if ((e.getOffset() < dot || e.getOffset() < mark) 1689 && selectionTag != null) { 1690 try { 1691 component.getHighlighter().changeHighlight(selectionTag, 1692 Math.min(dot, mark), Math.max(dot, mark)); 1693 } catch (BadLocationException e1) { 1694 e1.printStackTrace(); 1695 } 1696 } 1697 return; 1698 } 1699 int offs0 = e.getOffset(); 1700 int offs1 = offs0 + e.getLength(); 1701 int adjust = 0; 1702 int newDot = dot; 1703 boolean adjustDotBias = false; 1704 int newMark = mark; 1705 boolean adjustMarkBias = false; 1706 1707 if(e instanceof AbstractDocument.UndoRedoDocumentEvent ) { 1708 setDot(offs0); 1709 return; 1710 } 1711 if (newDot >= offs1) { 1712 newDot -= (offs1 - offs0); 1713 if(newDot == offs1) { 1714 adjustDotBias = true; 1715 } 1716 } else if (newDot >= offs0) { 1717 newDot = offs0; 1718 adjustDotBias = true; 1719 } 1720 if (newMark >= offs1) { 1721 newMark -= (offs1 - offs0); 1722 if(newMark == offs1) { 1723 adjustMarkBias = true; 1724 } 1725 } else if (newMark >= offs0) { 1726 newMark = offs0; 1727 adjustMarkBias = true; 1728 } 1729 if (newMark == newDot) { 1730 forceCaretPositionChange = true; 1731 try { 1732 setDot(newDot, guessBiasForOffset(newDot, dotBias, 1733 dotLTR)); 1734 } finally { 1735 forceCaretPositionChange = false; 1736 } 1737 ensureValidPosition(); 1738 } else { 1739 Position.Bias dotBias = DefaultCaret.this.dotBias; 1740 Position.Bias markBias = DefaultCaret.this.markBias; 1741 if(adjustDotBias) { 1742 dotBias = guessBiasForOffset(newDot, dotBias, dotLTR); 1743 } 1744 if(adjustMarkBias) { 1745 markBias = guessBiasForOffset(mark, markBias, markLTR); 1746 } 1747 setDot(newMark, markBias); 1748 if (getDot() == newMark) { 1749 moveDot(newDot, dotBias); 1752 } 1753 ensureValidPosition(); 1754 } 1755 } 1756 1757 1763 public void changedUpdate(DocumentEvent e) { 1764 if (getUpdatePolicy() == NEVER_UPDATE || 1765 (getUpdatePolicy() == UPDATE_WHEN_ON_EDT && 1766 !SwingUtilities.isEventDispatchThread())) { 1767 return; 1768 } 1769 if(e instanceof AbstractDocument.UndoRedoDocumentEvent ) { 1770 setDot(e.getOffset() + e.getLength()); 1771 } 1772 } 1773 1774 1776 1780 public void propertyChange(PropertyChangeEvent evt) { 1781 Object oldValue = evt.getOldValue(); 1782 Object newValue = evt.getNewValue(); 1783 if ((oldValue instanceof Document ) || (newValue instanceof Document )) { 1784 setDot(0); 1785 if (oldValue != null) { 1786 ((Document )oldValue).removeDocumentListener(this); 1787 } 1788 if (newValue != null) { 1789 ((Document )newValue).addDocumentListener(this); 1790 } 1791 } else if("enabled".equals(evt.getPropertyName())) { 1792 Boolean enabled = (Boolean ) evt.getNewValue(); 1793 if(component.isFocusOwner()) { 1794 if(enabled == Boolean.TRUE) { 1795 if(component.isEditable()) { 1796 setVisible(true); 1797 } 1798 setSelectionVisible(true); 1799 } else { 1800 setVisible(false); 1801 setSelectionVisible(false); 1802 } 1803 } 1804 } else if("caretWidth".equals(evt.getPropertyName())) { 1805 Integer newWidth = (Integer ) evt.getNewValue(); 1806 if (newWidth != null) { 1807 caretWidth = newWidth.intValue(); 1808 } else { 1809 caretWidth = -1; 1810 } 1811 repaint(); 1812 } else if("caretAspectRatio".equals(evt.getPropertyName())) { 1813 Number newRatio = (Number ) evt.getNewValue(); 1814 if (newRatio != null) { 1815 aspectRatio = newRatio.floatValue(); 1816 } else { 1817 aspectRatio = -1; 1818 } 1819 repaint(); 1820 } 1821 } 1822 1823 1824 1830 public void lostOwnership(Clipboard clipboard, 1831 Transferable contents) { 1832 if (ownsSelection) { 1833 ownsSelection = false; 1834 if (component != null && !component.hasFocus()) { 1835 setSelectionVisible(false); 1836 } 1837 } 1838 } 1839 } 1840 1841 1842 private class DefaultFilterBypass extends NavigationFilter.FilterBypass { 1843 public Caret getCaret() { 1844 return DefaultCaret.this; 1845 } 1846 1847 public void setDot(int dot, Position.Bias bias) { 1848 handleSetDot(dot, bias); 1849 } 1850 1851 public void moveDot(int dot, Position.Bias bias) { 1852 handleMoveDot(dot, bias); 1853 } 1854 } 1855} 1856 1857 | Popular Tags |