1 7 package javax.swing.text; 8 9 import java.lang.reflect.Method ; 10 11 import java.security.AccessController ; 12 import java.security.PrivilegedAction ; 13 14 import java.util.Collections ; 15 import java.util.HashMap ; 16 import java.util.Hashtable ; 17 import java.util.Enumeration ; 18 import java.util.Vector ; 19 import java.util.Iterator ; 20 import java.util.Map ; 21 import java.util.Map.Entry; 22 import java.util.Set ; 23 24 import java.io.*; 25 26 import java.awt.*; 27 import java.awt.event.*; 28 import java.awt.datatransfer.*; 29 import java.awt.im.InputContext ; 30 import java.awt.im.InputMethodRequests ; 31 import java.awt.font.TextHitInfo ; 32 import java.awt.font.TextAttribute ; 33 34 import java.text.*; 35 import java.text.AttributedCharacterIterator.Attribute; 36 37 import javax.swing.*; 38 import javax.swing.event.*; 39 import javax.swing.plaf.*; 40 41 import javax.accessibility.*; 42 43 import sun.awt.AppContext; 44 45 263 public abstract class JTextComponent extends JComponent implements Scrollable, Accessible 264 { 265 272 public JTextComponent() { 273 super(); 274 enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.INPUT_METHOD_EVENT_MASK); 276 caretEvent = new MutableCaretEvent(this); 277 addMouseListener(caretEvent); 278 addFocusListener(caretEvent); 279 setEditable(true); 280 setDragEnabled(false); 281 setLayout(null); updateUI(); 283 } 284 285 290 public TextUI getUI() { return (TextUI)ui; } 291 292 297 public void setUI(TextUI ui) { 298 super.setUI(ui); 299 } 300 301 307 public void updateUI() { 308 setUI((TextUI)UIManager.getUI(this)); 309 invalidate(); 310 } 311 312 319 public void addCaretListener(CaretListener listener) { 320 listenerList.add(CaretListener.class, listener); 321 } 322 323 329 public void removeCaretListener(CaretListener listener) { 330 listenerList.remove(CaretListener.class, listener); 331 } 332 333 346 public CaretListener[] getCaretListeners() { 347 return (CaretListener[])listenerList.getListeners(CaretListener.class); 348 } 349 350 360 protected void fireCaretUpdate(CaretEvent e) { 361 Object [] listeners = listenerList.getListenerList(); 363 for (int i = listeners.length-2; i>=0; i-=2) { 366 if (listeners[i]==CaretListener.class) { 367 ((CaretListener)listeners[i+1]).caretUpdate(e); 368 } 369 } 370 } 371 372 385 public void setDocument(Document doc) { 386 Document old = model; 387 388 392 try { 393 if (old instanceof AbstractDocument ) { 394 ((AbstractDocument )old).readLock(); 395 } 396 if (accessibleContext != null) { 397 model.removeDocumentListener( 398 ((AccessibleJTextComponent)accessibleContext)); 399 } 400 if (inputMethodRequestsHandler != null) { 401 model.removeDocumentListener((DocumentListener)inputMethodRequestsHandler); 402 } 403 model = doc; 404 405 Boolean runDir = getComponentOrientation().isLeftToRight() 408 ? TextAttribute.RUN_DIRECTION_LTR 409 : TextAttribute.RUN_DIRECTION_RTL; 410 doc.putProperty( TextAttribute.RUN_DIRECTION, runDir ); 411 412 firePropertyChange("document", old, doc); 413 } finally { 414 if (old instanceof AbstractDocument ) { 415 ((AbstractDocument )old).readUnlock(); 416 } 417 } 418 419 revalidate(); 420 repaint(); 421 if (accessibleContext != null) { 422 model.addDocumentListener( 423 ((AccessibleJTextComponent)accessibleContext)); 424 } 425 if (inputMethodRequestsHandler != null) { 426 model.addDocumentListener((DocumentListener)inputMethodRequestsHandler); 427 } 428 } 429 430 439 public Document getDocument() { 440 return model; 441 } 442 443 public void setComponentOrientation( ComponentOrientation o ) { 445 Document doc = getDocument(); 448 if( doc != null ) { 449 Boolean runDir = o.isLeftToRight() 450 ? TextAttribute.RUN_DIRECTION_LTR 451 : TextAttribute.RUN_DIRECTION_RTL; 452 doc.putProperty( TextAttribute.RUN_DIRECTION, runDir ); 453 } 454 super.setComponentOrientation( o ); 455 } 456 457 466 public Action [] getActions() { 467 return getUI().getEditorKit(this).getActions(); 468 } 469 470 485 public void setMargin(Insets m) { 486 Insets old = margin; 487 margin = m; 488 firePropertyChange("margin", old, m); 489 invalidate(); 490 } 491 492 498 public Insets getMargin() { 499 return margin; 500 } 501 502 509 public void setNavigationFilter(NavigationFilter filter) { 510 navigationFilter = filter; 511 } 512 513 522 public NavigationFilter getNavigationFilter() { 523 return navigationFilter; 524 } 525 526 532 public Caret getCaret() { 533 return caret; 534 } 535 536 549 public void setCaret(Caret c) { 550 if (caret != null) { 551 caret.removeChangeListener(caretEvent); 552 caret.deinstall(this); 553 } 554 Caret old = caret; 555 caret = c; 556 if (caret != null) { 557 caret.install(this); 558 caret.addChangeListener(caretEvent); 559 } 560 firePropertyChange("caret", old, caret); 561 } 562 563 568 public Highlighter getHighlighter() { 569 return highlighter; 570 } 571 572 587 public void setHighlighter(Highlighter h) { 588 if (highlighter != null) { 589 highlighter.deinstall(this); 590 } 591 Highlighter old = highlighter; 592 highlighter = h; 593 if (highlighter != null) { 594 highlighter.install(this); 595 } 596 firePropertyChange("highlighter", old, h); 597 } 598 599 612 public void setKeymap(Keymap map) { 613 Keymap old = keymap; 614 keymap = map; 615 firePropertyChange("keymap", old, keymap); 616 updateInputMap(old, map); 617 } 618 619 659 public void setDragEnabled(boolean b) { 660 if (b && GraphicsEnvironment.isHeadless()) { 661 throw new HeadlessException(); 662 } 663 dragEnabled = b; 664 } 665 666 673 public boolean getDragEnabled() { 674 return dragEnabled; 675 } 676 677 678 684 void updateInputMap(Keymap oldKm, Keymap newKm) { 685 InputMap km = getInputMap(JComponent.WHEN_FOCUSED); 687 InputMap last = km; 688 while (km != null && !(km instanceof KeymapWrapper)) { 689 last = km; 690 km = km.getParent(); 691 } 692 if (km != null) { 693 if (newKm == null) { 696 if (last != km) { 697 last.setParent(km.getParent()); 698 } 699 else { 700 last.setParent(null); 701 } 702 } 703 else { 704 InputMap newKM = new KeymapWrapper(newKm); 705 last.setParent(newKM); 706 if (last != km) { 707 newKM.setParent(km.getParent()); 708 } 709 } 710 } 711 else if (newKm != null) { 712 km = getInputMap(JComponent.WHEN_FOCUSED); 713 if (km != null) { 714 InputMap newKM = new KeymapWrapper(newKm); 717 newKM.setParent(km.getParent()); 718 km.setParent(newKM); 719 } 720 } 721 722 ActionMap am = getActionMap(); 724 ActionMap lastAM = am; 725 while (am != null && !(am instanceof KeymapActionMap)) { 726 lastAM = am; 727 am = am.getParent(); 728 } 729 if (am != null) { 730 if (newKm == null) { 733 if (lastAM != am) { 734 lastAM.setParent(am.getParent()); 735 } 736 else { 737 lastAM.setParent(null); 738 } 739 } 740 else { 741 ActionMap newAM = new KeymapActionMap(newKm); 742 lastAM.setParent(newAM); 743 if (lastAM != am) { 744 newAM.setParent(am.getParent()); 745 } 746 } 747 } 748 else if (newKm != null) { 749 am = getActionMap(); 750 if (am != null) { 751 ActionMap newAM = new KeymapActionMap(newKm); 754 newAM.setParent(am.getParent()); 755 am.setParent(newAM); 756 } 757 } 758 } 759 760 766 public Keymap getKeymap() { 767 return keymap; 768 } 769 770 785 public static Keymap addKeymap(String nm, Keymap parent) { 786 Keymap map = new DefaultKeymap(nm, parent); 787 if (nm != null) { 788 getKeymapTable().put(nm, map); 790 } 791 return map; 792 } 793 794 801 public static Keymap removeKeymap(String nm) { 802 return getKeymapTable().remove(nm); 803 } 804 805 812 public static Keymap getKeymap(String nm) { 813 return getKeymapTable().get(nm); 814 } 815 816 private static HashMap <String ,Keymap > getKeymapTable() { 817 AppContext appContext = AppContext.getAppContext(); 818 HashMap <String ,Keymap > keymapTable = 819 (HashMap <String ,Keymap >)appContext.get(KEYMAP_TABLE); 820 if (keymapTable == null) { 821 keymapTable = new HashMap <String ,Keymap >(17); 822 appContext.put(KEYMAP_TABLE, keymapTable); 823 Keymap binding = addKeymap(DEFAULT_KEYMAP, null); 825 binding.setDefaultAction(new 826 DefaultEditorKit.DefaultKeyTypedAction ()); 827 } 828 return keymapTable; 829 } 830 831 843 public static class KeyBinding { 844 845 848 public KeyStroke key; 849 850 853 public String actionName; 854 855 861 public KeyBinding(KeyStroke key, String actionName) { 862 this.key = key; 863 this.actionName = actionName; 864 } 865 } 866 867 902 public static void loadKeymap(Keymap map, KeyBinding[] bindings, Action [] actions) { 903 Hashtable h = new Hashtable (); 904 for (int i = 0; i < actions.length; i++) { 905 Action a = actions[i]; 906 String value = (String )a.getValue(Action.NAME); 907 h.put((value!=null ? value:""), a); 908 } 909 for (int i = 0; i < bindings.length; i++) { 910 Action a = (Action ) h.get(bindings[i].actionName); 911 if (a != null) { 912 map.addActionForKeyStroke(bindings[i].key, a); 913 } 914 } 915 } 916 917 924 private static Boolean isProcessInputMethodEventOverridden(Class klass) { 925 if (klass == JTextComponent .class) { 926 return Boolean.FALSE; 927 } 928 Boolean retValue = (Boolean )overrideMap.get(klass.getName()); 929 930 if (retValue != null) { 931 return retValue; 932 } 933 Boolean sOverriden = isProcessInputMethodEventOverridden( 934 klass.getSuperclass()); 935 936 if (sOverriden.booleanValue()) { 937 overrideMap.put(klass.getName(), sOverriden); 940 return sOverriden; 941 } 942 try { 945 Class [] classes = new Class [1]; 946 classes[0] = InputMethodEvent.class; 947 948 Method m = klass.getDeclaredMethod("processInputMethodEvent", 949 classes); 950 retValue = Boolean.TRUE; 951 } catch (NoSuchMethodException nsme) { 952 retValue = Boolean.FALSE; 953 } 954 overrideMap.put(klass.getName(), retValue); 955 return retValue; 956 } 957 958 964 public Color getCaretColor() { 965 return caretColor; 966 } 967 968 981 public void setCaretColor(Color c) { 982 Color old = caretColor; 983 caretColor = c; 984 firePropertyChange("caretColor", old, caretColor); 985 } 986 987 993 public Color getSelectionColor() { 994 return selectionColor; 995 } 996 997 1010 public void setSelectionColor(Color c) { 1011 Color old = selectionColor; 1012 selectionColor = c; 1013 firePropertyChange("selectionColor", old, selectionColor); 1014 } 1015 1016 1022 public Color getSelectedTextColor() { 1023 return selectedTextColor; 1024 } 1025 1026 1039 public void setSelectedTextColor(Color c) { 1040 Color old = selectedTextColor; 1041 selectedTextColor = c; 1042 firePropertyChange("selectedTextColor", old, selectedTextColor); 1043 } 1044 1045 1051 public Color getDisabledTextColor() { 1052 return disabledTextColor; 1053 } 1054 1055 1067 public void setDisabledTextColor(Color c) { 1068 Color old = disabledTextColor; 1069 disabledTextColor = c; 1070 firePropertyChange("disabledTextColor", old, disabledTextColor); 1071 } 1072 1073 1091 public void replaceSelection(String content) { 1092 Document doc = getDocument(); 1093 if (doc != null) { 1094 try { 1095 boolean composedTextSaved = saveComposedText(caret.getDot()); 1096 int p0 = Math.min(caret.getDot(), caret.getMark()); 1097 int p1 = Math.max(caret.getDot(), caret.getMark()); 1098 if (doc instanceof AbstractDocument ) { 1099 ((AbstractDocument )doc).replace(p0, p1 - p0, content,null); 1100 } 1101 else { 1102 if (p0 != p1) { 1103 doc.remove(p0, p1 - p0); 1104 } 1105 if (content != null && content.length() > 0) { 1106 doc.insertString(p0, content, null); 1107 } 1108 } 1109 if (composedTextSaved) { 1110 restoreComposedText(); 1111 } 1112 } catch (BadLocationException e) { 1113 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this); 1114 } 1115 } 1116 } 1117 1118 1127 public String getText(int offs, int len) throws BadLocationException { 1128 return getDocument().getText(offs, len); 1129 } 1130 1131 1147 public Rectangle modelToView(int pos) throws BadLocationException { 1148 return getUI().modelToView(this, pos); 1149 } 1150 1151 1165 public int viewToModel(Point pt) { 1166 return getUI().viewToModel(this, pt); 1167 } 1168 1169 1178 public void cut() { 1179 if (isEditable() && isEnabled()) { 1180 invokeAction("cut", TransferHandler.getCutAction()); 1181 } 1182 } 1183 1184 1193 public void copy() { 1194 invokeAction("copy", TransferHandler.getCopyAction()); 1195 } 1196 1197 1209 public void paste() { 1210 if (isEditable() && isEnabled()) { 1211 invokeAction("paste", TransferHandler.getPasteAction()); 1212 } 1213 } 1214 1215 1222 private void invokeAction(String name, Action altAction) { 1223 ActionMap map = getActionMap(); 1224 Action action = null; 1225 1226 if (map != null) { 1227 action = map.get(name); 1228 } 1229 if (action == null) { 1230 installDefaultTransferHandlerIfNecessary(); 1231 action = altAction; 1232 } 1233 action.actionPerformed(new ActionEvent(this, 1234 ActionEvent.ACTION_PERFORMED, (String )action. 1235 getValue(Action.NAME), 1236 EventQueue.getMostRecentEventTime(), 1237 getCurrentEventModifiers())); 1238 } 1239 1240 1244 private void installDefaultTransferHandlerIfNecessary() { 1245 if (getTransferHandler() == null) { 1246 if (defaultTransferHandler == null) { 1247 defaultTransferHandler = new DefaultTransferHandler(); 1248 } 1249 setTransferHandler(defaultTransferHandler); 1250 } 1251 } 1252 1253 1267 public void moveCaretPosition(int pos) { 1268 Document doc = getDocument(); 1269 if (doc != null) { 1270 if (pos > doc.getLength() || pos < 0) { 1271 throw new IllegalArgumentException ("bad position: " + pos); 1272 } 1273 caret.moveDot(pos); 1274 } 1275 } 1276 1277 1280 public static final String FOCUS_ACCELERATOR_KEY = "focusAcceleratorKey"; 1281 1282 1298 public void setFocusAccelerator(char aKey) { 1299 aKey = Character.toUpperCase(aKey); 1300 char old = focusAccelerator; 1301 focusAccelerator = aKey; 1302 firePropertyChange(FOCUS_ACCELERATOR_KEY, old, focusAccelerator); 1306 firePropertyChange("focusAccelerator", old, focusAccelerator); 1307 } 1308 1309 1316 public char getFocusAccelerator() { 1317 return focusAccelerator; 1318 } 1319 1320 1339 public void read(Reader in, Object desc) throws IOException { 1340 EditorKit kit = getUI().getEditorKit(this); 1341 Document doc = kit.createDefaultDocument(); 1342 if (desc != null) { 1343 doc.putProperty(Document.StreamDescriptionProperty, desc); 1344 } 1345 try { 1346 kit.read(in, doc, 0); 1347 setDocument(doc); 1348 } catch (BadLocationException e) { 1349 throw new IOException(e.getMessage()); 1350 } 1351 } 1352 1353 1361 public void write(Writer out) throws IOException { 1362 Document doc = getDocument(); 1363 try { 1364 getUI().getEditorKit(this).write(out, doc, 0, doc.getLength()); 1365 } catch (BadLocationException e) { 1366 throw new IOException(e.getMessage()); 1367 } 1368 } 1369 1370 public void removeNotify() { 1371 super.removeNotify(); 1372 if (getFocusedComponent() == this) { 1373 AppContext.getAppContext().remove(FOCUSED_COMPONENT); 1374 } 1375 } 1376 1377 1379 1394 public void setCaretPosition(int position) { 1395 Document doc = getDocument(); 1396 if (doc != null) { 1397 if (position > doc.getLength() || position < 0) { 1398 throw new IllegalArgumentException ("bad position: " + position); 1399 } 1400 caret.setDot(position); 1401 } 1402 } 1403 1404 1411 public int getCaretPosition() { 1412 return caret.getDot(); 1413 } 1414 1415 1437 public void setText(String t) { 1438 try { 1439 Document doc = getDocument(); 1440 if (doc instanceof AbstractDocument ) { 1441 ((AbstractDocument )doc).replace(0, doc.getLength(), t,null); 1442 } 1443 else { 1444 doc.remove(0, doc.getLength()); 1445 doc.insertString(0, t, null); 1446 } 1447 } catch (BadLocationException e) { 1448 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this); 1449 } 1450 } 1451 1452 1465 public String getText() { 1466 Document doc = getDocument(); 1467 String txt; 1468 try { 1469 txt = doc.getText(0, doc.getLength()); 1470 } catch (BadLocationException e) { 1471 txt = null; 1472 } 1473 return txt; 1474 } 1475 1476 1486 public String getSelectedText() { 1487 String txt = null; 1488 int p0 = Math.min(caret.getDot(), caret.getMark()); 1489 int p1 = Math.max(caret.getDot(), caret.getMark()); 1490 if (p0 != p1) { 1491 try { 1492 Document doc = getDocument(); 1493 txt = doc.getText(p0, p1 - p0); 1494 } catch (BadLocationException e) { 1495 throw new IllegalArgumentException (e.getMessage()); 1496 } 1497 } 1498 return txt; 1499 } 1500 1501 1508 public boolean isEditable() { 1509 return editable; 1510 } 1511 1512 1524 public void setEditable(boolean b) { 1525 if (b != editable) { 1526 boolean oldVal = editable; 1527 editable = b; 1528 if (editable) { 1529 setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); 1530 } else { 1531 setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); 1532 } 1533 enableInputMethods(editable); 1534 firePropertyChange("editable", Boolean.valueOf(oldVal), Boolean.valueOf(editable)); 1535 repaint(); 1536 } 1537 } 1538 1539 1545 public int getSelectionStart() { 1546 int start = Math.min(caret.getDot(), caret.getMark()); 1547 return start; 1548 } 1549 1550 1564 public void setSelectionStart(int selectionStart) { 1565 1568 select(selectionStart, getSelectionEnd()); 1569 } 1570 1571 1577 public int getSelectionEnd() { 1578 int end = Math.max(caret.getDot(), caret.getMark()); 1579 return end; 1580 } 1581 1582 1596 public void setSelectionEnd(int selectionEnd) { 1597 1600 select(getSelectionStart(), selectionEnd); 1601 } 1602 1603 1631 public void select(int selectionStart, int selectionEnd) { 1632 int docLength = getDocument().getLength(); 1634 1635 if (selectionStart < 0) { 1636 selectionStart = 0; 1637 } 1638 if (selectionStart > docLength) { 1639 selectionStart = docLength; 1640 } 1641 if (selectionEnd > docLength) { 1642 selectionEnd = docLength; 1643 } 1644 if (selectionEnd < selectionStart) { 1645 selectionEnd = selectionStart; 1646 } 1647 1648 setCaretPosition(selectionStart); 1649 moveCaretPosition(selectionEnd); 1650 } 1651 1652 1656 public void selectAll() { 1657 Document doc = getDocument(); 1658 if (doc != null) { 1659 setCaretPosition(0); 1660 moveCaretPosition(doc.getLength()); 1661 } 1662 } 1663 1664 1666 1688 public String getToolTipText(MouseEvent event) { 1689 String retValue = super.getToolTipText(event); 1690 1691 if (retValue == null) { 1692 TextUI ui = getUI(); 1693 if (ui != null) { 1694 retValue = ui.getToolTipText(this, new Point(event.getX(), 1695 event.getY())); 1696 } 1697 } 1698 return retValue; 1699 } 1700 1701 1703 1711 public Dimension getPreferredScrollableViewportSize() { 1712 return getPreferredSize(); 1713 } 1714 1715 1716 1736 public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) { 1737 switch(orientation) { 1738 case SwingConstants.VERTICAL: 1739 return visibleRect.height / 10; 1740 case SwingConstants.HORIZONTAL: 1741 return visibleRect.width / 10; 1742 default: 1743 throw new IllegalArgumentException ("Invalid orientation: " + orientation); 1744 } 1745 } 1746 1747 1748 1766 public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) { 1767 switch(orientation) { 1768 case SwingConstants.VERTICAL: 1769 return visibleRect.height; 1770 case SwingConstants.HORIZONTAL: 1771 return visibleRect.width; 1772 default: 1773 throw new IllegalArgumentException ("Invalid orientation: " + orientation); 1774 } 1775 } 1776 1777 1778 1794 public boolean getScrollableTracksViewportWidth() { 1795 if (getParent() instanceof JViewport) { 1796 return (((JViewport)getParent()).getWidth() > getPreferredSize().width); 1797 } 1798 return false; 1799 } 1800 1801 1814 public boolean getScrollableTracksViewportHeight() { 1815 if (getParent() instanceof JViewport) { 1816 return (((JViewport)getParent()).getHeight() > getPreferredSize().height); 1817 } 1818 return false; 1819 } 1820 1821 1825 1826 1838 public AccessibleContext getAccessibleContext() { 1839 if (accessibleContext == null) { 1840 accessibleContext = new AccessibleJTextComponent(); 1841 } 1842 return accessibleContext; 1843 } 1844 1845 1859 public class AccessibleJTextComponent extends AccessibleJComponent 1860 implements AccessibleText, CaretListener, DocumentListener, 1861 AccessibleAction, AccessibleEditableText { 1862 1863 int caretPos; 1864 Point oldLocationOnScreen; 1865 1866 1870 public AccessibleJTextComponent() { 1871 Document doc = JTextComponent.this.getDocument(); 1872 if (doc != null) { 1873 doc.addDocumentListener(this); 1874 } 1875 JTextComponent.this.addCaretListener(this); 1876 caretPos = getCaretPosition(); 1877 1878 try { 1879 oldLocationOnScreen = getLocationOnScreen(); 1880 } catch (IllegalComponentStateException iae) { 1881 } 1882 1883 JTextComponent.this.addComponentListener(new ComponentAdapter() { 1888 1889 public void componentMoved(ComponentEvent e) { 1890 try { 1891 Point newLocationOnScreen = getLocationOnScreen(); 1892 firePropertyChange(ACCESSIBLE_VISIBLE_DATA_PROPERTY, 1893 oldLocationOnScreen, 1894 newLocationOnScreen); 1895 1896 oldLocationOnScreen = newLocationOnScreen; 1897 } catch (IllegalComponentStateException iae) { 1898 } 1899 } 1900 }); 1901 } 1902 1903 1912 public void caretUpdate(CaretEvent e) { 1913 int dot = e.getDot(); 1914 int mark = e.getMark(); 1915 if (caretPos != dot) { 1916 firePropertyChange(ACCESSIBLE_CARET_PROPERTY, 1918 new Integer (caretPos), new Integer (dot)); 1919 caretPos = dot; 1920 1921 try { 1922 oldLocationOnScreen = getLocationOnScreen(); 1923 } catch (IllegalComponentStateException iae) { 1924 } 1925 } 1926 if (mark != dot) { 1927 firePropertyChange(ACCESSIBLE_SELECTION_PROPERTY, null, 1929 getSelectedText()); 1930 } 1931 } 1932 1933 1935 1942 public void insertUpdate(DocumentEvent e) { 1943 final Integer pos = new Integer (e.getOffset()); 1944 if (SwingUtilities.isEventDispatchThread()) { 1945 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); 1946 } else { 1947 Runnable doFire = new Runnable () { 1948 public void run() { 1949 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, 1950 null, pos); 1951 } 1952 }; 1953 SwingUtilities.invokeLater(doFire); 1954 } 1955 } 1956 1957 1964 public void removeUpdate(DocumentEvent e) { 1965 final Integer pos = new Integer (e.getOffset()); 1966 if (SwingUtilities.isEventDispatchThread()) { 1967 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); 1968 } else { 1969 Runnable doFire = new Runnable () { 1970 public void run() { 1971 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, 1972 null, pos); 1973 } 1974 }; 1975 SwingUtilities.invokeLater(doFire); 1976 } 1977 } 1978 1979 1986 public void changedUpdate(DocumentEvent e) { 1987 final Integer pos = new Integer (e.getOffset()); 1988 if (SwingUtilities.isEventDispatchThread()) { 1989 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, null, pos); 1990 } else { 1991 Runnable doFire = new Runnable () { 1992 public void run() { 1993 firePropertyChange(ACCESSIBLE_TEXT_PROPERTY, 1994 null, pos); 1995 } 1996 }; 1997 SwingUtilities.invokeLater(doFire); 1998 } 1999 } 2000 2001 2014 public AccessibleStateSet getAccessibleStateSet() { 2015 AccessibleStateSet states = super.getAccessibleStateSet(); 2016 if (JTextComponent.this.isEditable()) { 2017 states.add(AccessibleState.EDITABLE); 2018 } 2019 return states; 2020 } 2021 2022 2023 2030 public AccessibleRole getAccessibleRole() { 2031 return AccessibleRole.TEXT; 2032 } 2033 2034 2042 public AccessibleText getAccessibleText() { 2043 return this; 2044 } 2045 2046 2047 2049 2053 2054 2062 public int getIndexAtPoint(Point p) { 2063 if (p == null) { 2064 return -1; 2065 } 2066 return JTextComponent.this.viewToModel(p); 2067 } 2068 2069 2076 Rectangle getRootEditorRect() { 2077 Rectangle alloc = JTextComponent.this.getBounds(); 2078 if ((alloc.width > 0) && (alloc.height > 0)) { 2079 alloc.x = alloc.y = 0; 2080 Insets insets = JTextComponent.this.getInsets(); 2081 alloc.x += insets.left; 2082 alloc.y += insets.top; 2083 alloc.width -= insets.left + insets.right; 2084 alloc.height -= insets.top + insets.bottom; 2085 return alloc; 2086 } 2087 return null; 2088 } 2089 2090 2118 public Rectangle getCharacterBounds(int i) { 2119 if (i < 0 || i > model.getLength()-1) { 2120 return null; 2121 } 2122 TextUI ui = getUI(); 2123 if (ui == null) { 2124 return null; 2125 } 2126 Rectangle rect = null; 2127 Rectangle alloc = getRootEditorRect(); 2128 if (alloc == null) { 2129 return null; 2130 } 2131 if (model instanceof AbstractDocument ) { 2132 ((AbstractDocument )model).readLock(); 2133 } 2134 try { 2135 View rootView = ui.getRootView(JTextComponent.this); 2136 if (rootView != null) { 2137 rootView.setSize(alloc.width, alloc.height); 2138 2139 Shape bounds = rootView.modelToView(i, 2140 Position.Bias.Forward, i+1, 2141 Position.Bias.Backward, alloc); 2142 2143 rect = (bounds instanceof Rectangle) ? 2144 (Rectangle)bounds : bounds.getBounds(); 2145 2146 } 2147 } catch (BadLocationException e) { 2148 } finally { 2149 if (model instanceof AbstractDocument ) { 2150 ((AbstractDocument )model).readUnlock(); 2151 } 2152 } 2153 return rect; 2154 } 2155 2156 2161 public int getCharCount() { 2162 return model.getLength(); 2163 } 2164 2165 2174 public int getCaretPosition() { 2175 return JTextComponent.this.getCaretPosition(); 2176 } 2177 2178 2184 public AttributeSet getCharacterAttribute(int i) { 2185 Element e = null; 2186 if (model instanceof AbstractDocument ) { 2187 ((AbstractDocument )model).readLock(); 2188 } 2189 try { 2190 for (e = model.getDefaultRootElement(); ! e.isLeaf(); ) { 2191 int index = e.getElementIndex(i); 2192 e = e.getElement(index); 2193 } 2194 } finally { 2195 if (model instanceof AbstractDocument ) { 2196 ((AbstractDocument )model).readUnlock(); 2197 } 2198 } 2199 return e.getAttributes(); 2200 } 2201 2202 2203 2212 public int getSelectionStart() { 2213 return JTextComponent.this.getSelectionStart(); 2214 } 2215 2216 2225 public int getSelectionEnd() { 2226 return JTextComponent.this.getSelectionEnd(); 2227 } 2228 2229 2234 public String getSelectedText() { 2235 return JTextComponent.this.getSelectedText(); 2236 } 2237 2238 2242 private class IndexedSegment extends Segment { 2243 2246 public int modelOffset; 2247 } 2248 2249 2250 2260 public String getAtIndex(int part, int index) { 2261 return getAtIndex(part, index, 0); 2262 } 2263 2264 2265 2273 public String getAfterIndex(int part, int index) { 2274 return getAtIndex(part, index, 1); 2275 } 2276 2277 2278 2286 public String getBeforeIndex(int part, int index) { 2287 return getAtIndex(part, index, -1); 2288 } 2289 2290 2291 2296 private String getAtIndex(int part, int index, int direction) { 2297 if (model instanceof AbstractDocument ) { 2298 ((AbstractDocument )model).readLock(); 2299 } 2300 try { 2301 if (index < 0 || index >= model.getLength()) { 2302 return null; 2303 } 2304 switch (part) { 2305 case AccessibleText.CHARACTER: 2306 if (index + direction < model.getLength() && 2307 index + direction >= 0) { 2308 return model.getText(index + direction, 1); 2309 } 2310 break; 2311 2312 2313 case AccessibleText.WORD: 2314 case AccessibleText.SENTENCE: 2315 IndexedSegment seg = getSegmentAt(part, index); 2316 if (seg != null) { 2317 if (direction != 0) { 2318 int next; 2319 2320 2321 if (direction < 0) { 2322 next = seg.modelOffset - 1; 2323 } 2324 else { 2325 next = seg.modelOffset + direction * seg.count; 2326 } 2327 if (next >= 0 && next <= model.getLength()) { 2328 seg = getSegmentAt(part, next); 2329 } 2330 else { 2331 seg = null; 2332 } 2333 } 2334 if (seg != null) { 2335 return new String (seg.array, seg.offset, 2336 seg.count); 2337 } 2338 } 2339 break; 2340 2341 2342 default: 2343 break; 2344 } 2345 } catch (BadLocationException e) { 2346 } finally { 2347 if (model instanceof AbstractDocument ) { 2348 ((AbstractDocument )model).readUnlock(); 2349 } 2350 } 2351 return null; 2352 } 2353 2354 2355 2358 private Element getParagraphElement(int index) { 2359 if (model instanceof PlainDocument ) { 2360 PlainDocument sdoc = (PlainDocument )model; 2361 return sdoc.getParagraphElement(index); 2362 } else if (model instanceof StyledDocument ) { 2363 StyledDocument sdoc = (StyledDocument )model; 2364 return sdoc.getParagraphElement(index); 2365 } else { 2366 Element para = null; 2367 for (para = model.getDefaultRootElement(); ! para.isLeaf(); ) { 2368 int pos = para.getElementIndex(index); 2369 para = para.getElement(pos); 2370 } 2371 if (para == null) { 2372 return null; 2373 } 2374 return para.getParentElement(); 2375 } 2376 } 2377 2378 2383 private IndexedSegment getParagraphElementText(int index) 2384 throws BadLocationException { 2385 Element para = getParagraphElement(index); 2386 2387 2388 if (para != null) { 2389 IndexedSegment segment = new IndexedSegment(); 2390 try { 2391 int length = para.getEndOffset() - para.getStartOffset(); 2392 model.getText(para.getStartOffset(), length, segment); 2393 } catch (BadLocationException e) { 2394 return null; 2395 } 2396 segment.modelOffset = para.getStartOffset(); 2397 return segment; 2398 } 2399 return null; 2400 } 2401 2402 2403 2411 private IndexedSegment getSegmentAt(int part, int index) throws 2412 BadLocationException { 2413 IndexedSegment seg = getParagraphElementText(index); 2414 if (seg == null) { 2415 return null; 2416 } 2417 BreakIterator iterator; 2418 switch (part) { 2419 case AccessibleText.WORD: 2420 iterator = BreakIterator.getWordInstance(getLocale()); 2421 break; 2422 case AccessibleText.SENTENCE: 2423 iterator = BreakIterator.getSentenceInstance(getLocale()); 2424 break; 2425 default: 2426 return null; 2427 } 2428 seg.first(); 2429 iterator.setText(seg); 2430 int end = iterator.following(index - seg.modelOffset + seg.offset); 2431 if (end == BreakIterator.DONE) { 2432 return null; 2433 } 2434 if (end > seg.offset + seg.count) { 2435 return null; 2436 } 2437 int begin = iterator.previous(); 2438 if (begin == BreakIterator.DONE || 2439 begin >= seg.offset + seg.count) { 2440 return null; 2441 } 2442 seg.modelOffset = seg.modelOffset + begin - seg.offset; 2443 seg.offset = begin; 2444 seg.count = end - begin; 2445 return seg; 2446 } 2447 2448 2450 2456 public AccessibleEditableText getAccessibleEditableText() { 2457 return this; 2458 } 2459 2460 2465 public void setTextContents(String s) { 2466 JTextComponent.this.setText(s); 2467 } 2468 2469 2476 public void insertTextAtIndex(int index, String s) { 2477 Document doc = JTextComponent.this.getDocument(); 2478 if (doc != null) { 2479 try { 2480 if (s != null && s.length() > 0) { 2481 boolean composedTextSaved = saveComposedText(index); 2482 doc.insertString(index, s, null); 2483 if (composedTextSaved) { 2484 restoreComposedText(); 2485 } 2486 } 2487 } catch (BadLocationException e) { 2488 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this); 2489 } 2490 } 2491 } 2492 2493 2500 public String getTextRange(int startIndex, int endIndex) { 2501 String txt = null; 2502 int p0 = Math.min(startIndex, endIndex); 2503 int p1 = Math.max(startIndex, endIndex); 2504 if (p0 != p1) { 2505 try { 2506 Document doc = JTextComponent.this.getDocument(); 2507 txt = doc.getText(p0, p1 - p0); 2508 } catch (BadLocationException e) { 2509 throw new IllegalArgumentException (e.getMessage()); 2510 } 2511 } 2512 return txt; 2513 } 2514 2515 2521 public void delete(int startIndex, int endIndex) { 2522 if (isEditable() && isEnabled()) { 2523 try { 2524 int p0 = Math.min(startIndex, endIndex); 2525 int p1 = Math.max(startIndex, endIndex); 2526 if (p0 != p1) { 2527 Document doc = getDocument(); 2528 doc.remove(p0, p1 - p0); 2529 } 2530 } catch (BadLocationException e) { 2531 } 2532 } else { 2533 UIManager.getLookAndFeel().provideErrorFeedback(JTextComponent.this); 2534 } 2535 } 2536 2537 2543 public void cut(int startIndex, int endIndex) { 2544 selectText(startIndex, endIndex); 2545 JTextComponent.this.cut(); 2546 } 2547 2548 2554 public void paste(int startIndex) { 2555 setCaretPosition(startIndex); 2556 JTextComponent.this.paste(); 2557 } 2558 2559 2567 public void replaceText(int startIndex, int endIndex, String s) { 2568 selectText(startIndex, endIndex); 2569 JTextComponent.this.replaceSelection(s); 2570 } 2571 2572 2578 public void selectText(int startIndex, int endIndex) { 2579 JTextComponent.this.select(startIndex, endIndex); 2580 } 2581 2582 2590 public void setAttributes(int startIndex, int endIndex, 2591 AttributeSet as) { 2592 2593 Document doc = JTextComponent.this.getDocument(); 2595 if (doc != null && doc instanceof StyledDocument ) { 2596 StyledDocument sDoc = (StyledDocument )doc; 2597 int offset = startIndex; 2598 int length = endIndex - startIndex; 2599 sDoc.setCharacterAttributes(offset, length, as, true); 2600 } 2601 } 2602 2603 2605 2606 2608 public AccessibleAction getAccessibleAction() { 2609 return this; 2610 } 2611 2612 2619 public int getAccessibleActionCount() { 2620 Action [] actions = JTextComponent.this.getActions(); 2621 return actions.length; 2622 } 2623 2624 2631 public String getAccessibleActionDescription(int i) { 2632 Action [] actions = JTextComponent.this.getActions(); 2633 if (i < 0 || i >= actions.length) { 2634 return null; 2635 } 2636 return (String )actions[i].getValue(Action.NAME); 2637 } 2638 2639 2646 public boolean doAccessibleAction(int i) { 2647 Action [] actions = JTextComponent.this.getActions(); 2648 if (i < 0 || i >= actions.length) { 2649 return false; 2650 } 2651 ActionEvent ae = 2652 new ActionEvent(JTextComponent.this, 2653 ActionEvent.ACTION_PERFORMED, null, 2654 EventQueue.getMostRecentEventTime(), 2655 getCurrentEventModifiers()); 2656 actions[i].actionPerformed(ae); 2657 return true; 2658 } 2659 2660 2662 2663 } 2664 2665 2666 2668 private void readObject(ObjectInputStream s) 2669 throws IOException, ClassNotFoundException 2670 { 2671 s.defaultReadObject(); 2672 caretEvent = new MutableCaretEvent(this); 2673 addMouseListener(caretEvent); 2674 addFocusListener(caretEvent); 2675 } 2676 2677 2679 2682 private Document model; 2683 2684 2692 private transient Caret caret; 2693 2694 2697 private NavigationFilter navigationFilter; 2698 2699 2706 private transient Highlighter highlighter; 2707 2708 2715 private transient Keymap keymap; 2716 2717 private transient MutableCaretEvent caretEvent; 2718 private Color caretColor; 2719 private Color selectionColor; 2720 private Color selectedTextColor; 2721 private Color disabledTextColor; 2722 private boolean editable; 2723 private Insets margin; 2724 private char focusAccelerator; 2725 private boolean dragEnabled; 2726 2727 2730 private static DefaultTransferHandler defaultTransferHandler; 2731 2732 2736 private static Map overrideMap; 2737 2738 2750 protected String paramString() { 2751 String editableString = (editable ? 2752 "true" : "false"); 2753 String caretColorString = (caretColor != null ? 2754 caretColor.toString() : ""); 2755 String selectionColorString = (selectionColor != null ? 2756 selectionColor.toString() : ""); 2757 String selectedTextColorString = (selectedTextColor != null ? 2758 selectedTextColor.toString() : ""); 2759 String disabledTextColorString = (disabledTextColor != null ? 2760 disabledTextColor.toString() : ""); 2761 String marginString = (margin != null ? 2762 margin.toString() : ""); 2763 2764 return super.paramString() + 2765 ",caretColor=" + caretColorString + 2766 ",disabledTextColor=" + disabledTextColorString + 2767 ",editable=" + editableString + 2768 ",margin=" + marginString + 2769 ",selectedTextColor=" + selectedTextColorString + 2770 ",selectionColor=" + selectionColorString; 2771 } 2772 2773 2774 2780 static class DefaultTransferHandler extends TransferHandler implements 2781 UIResource { 2782 public void exportToClipboard(JComponent comp, Clipboard clipboard, 2783 int action) throws IllegalStateException { 2784 if (comp instanceof JTextComponent ) { 2785 JTextComponent text = (JTextComponent )comp; 2786 int p0 = text.getSelectionStart(); 2787 int p1 = text.getSelectionEnd(); 2788 if (p0 != p1) { 2789 try { 2790 Document doc = text.getDocument(); 2791 String srcData = doc.getText(p0, p1 - p0); 2792 StringSelection contents =new StringSelection(srcData); 2793 2794 clipboard.setContents(contents, null); 2798 2799 if (action == TransferHandler.MOVE) { 2800 doc.remove(p0, p1 - p0); 2801 } 2802 } catch (BadLocationException ble) {} 2803 } 2804 } 2805 } 2806 public boolean importData(JComponent comp, Transferable t) { 2807 if (comp instanceof JTextComponent ) { 2808 DataFlavor flavor = getFlavor(t.getTransferDataFlavors()); 2809 2810 if (flavor != null) { 2811 InputContext ic = comp.getInputContext(); 2812 if (ic != null) { 2813 ic.endComposition(); 2814 } 2815 try { 2816 String data = (String )t.getTransferData(flavor); 2817 2818 ((JTextComponent )comp).replaceSelection(data); 2819 return true; 2820 } catch (UnsupportedFlavorException ufe) { 2821 } catch (IOException ioe) { 2822 } 2823 } 2824 } 2825 return false; 2826 } 2827 public boolean canImport(JComponent comp, 2828 DataFlavor[] transferFlavors) { 2829 JTextComponent c = (JTextComponent )comp; 2830 if (!(c.isEditable() && c.isEnabled())) { 2831 return false; 2832 } 2833 return (getFlavor(transferFlavors) != null); 2834 } 2835 public int getSourceActions(JComponent c) { 2836 return NONE; 2837 } 2838 private DataFlavor getFlavor(DataFlavor[] flavors) { 2839 if (flavors != null) { 2840 for (int counter = 0; counter < flavors.length; counter++) { 2841 if (flavors[counter].equals(DataFlavor.stringFlavor)) { 2842 return flavors[counter]; 2843 } 2844 } 2845 } 2846 return null; 2847 } 2848 } 2849 2850 2854 static final JTextComponent getFocusedComponent() { 2855 return (JTextComponent )AppContext.getAppContext(). 2856 get(FOCUSED_COMPONENT); 2857 } 2858 2859 private int getCurrentEventModifiers() { 2860 int modifiers = 0; 2861 AWTEvent currentEvent = EventQueue.getCurrentEvent(); 2862 if (currentEvent instanceof InputEvent) { 2863 modifiers = ((InputEvent)currentEvent).getModifiers(); 2864 } else if (currentEvent instanceof ActionEvent) { 2865 modifiers = ((ActionEvent)currentEvent).getModifiers(); 2866 } 2867 return modifiers; 2868 } 2869 2870 private static final Object KEYMAP_TABLE = 2871 new StringBuilder ("JTextComponent_KeymapTable"); 2872 private JTextComponent editor; 2873 private transient InputMethodRequests inputMethodRequestsHandler; 2878 private SimpleAttributeSet composedTextAttribute; 2879 private String composedTextContent; 2880 private Position composedTextStart; 2881 private Position composedTextEnd; 2882 private Position latestCommittedTextStart; 2883 private Position latestCommittedTextEnd; 2884 private ComposedTextCaret composedTextCaret; 2885 private transient Caret originalCaret; 2886 2890 private boolean checkedInputOverride; 2891 private boolean needToSendKeyTypedEvent; 2892 2893 static class DefaultKeymap implements Keymap { 2894 2895 DefaultKeymap(String nm, Keymap parent) { 2896 this.nm = nm; 2897 this.parent = parent; 2898 bindings = new Hashtable (); 2899 } 2900 2901 2909 public Action getDefaultAction() { 2910 if (defaultAction != null) { 2911 return defaultAction; 2912 } 2913 return (parent != null) ? parent.getDefaultAction() : null; 2914 } 2915 2916 2919 public void setDefaultAction(Action a) { 2920 defaultAction = a; 2921 } 2922 2923 public String getName() { 2924 return nm; 2925 } 2926 2927 public Action getAction(KeyStroke key) { 2928 Action a = (Action ) bindings.get(key); 2929 if ((a == null) && (parent != null)) { 2930 a = parent.getAction(key); 2931 } 2932 return a; 2933 } 2934 2935 public KeyStroke[] getBoundKeyStrokes() { 2936 KeyStroke[] keys = new KeyStroke[bindings.size()]; 2937 int i = 0; 2938 for (Enumeration e = bindings.keys() ; e.hasMoreElements() ;) { 2939 keys[i++] = (KeyStroke) e.nextElement(); 2940 } 2941 return keys; 2942 } 2943 2944 public Action [] getBoundActions() { 2945 Action [] actions = new Action [bindings.size()]; 2946 int i = 0; 2947 for (Enumeration e = bindings.elements() ; e.hasMoreElements() ;) { 2948 actions[i++] = (Action ) e.nextElement(); 2949 } 2950 return actions; 2951 } 2952 2953 public KeyStroke[] getKeyStrokesForAction(Action a) { 2954 if (a == null) { 2955 return null; 2956 } 2957 KeyStroke[] retValue = null; 2958 Vector keyStrokes = null; 2960 for (Enumeration enum_ = bindings.keys(); 2961 enum_.hasMoreElements();) { 2962 Object key = enum_.nextElement(); 2963 if (bindings.get(key) == a) { 2964 if (keyStrokes == null) { 2965 keyStrokes = new Vector (); 2966 } 2967 keyStrokes.addElement(key); 2968 } 2969 } 2970 if (parent != null) { 2972 KeyStroke[] pStrokes = parent.getKeyStrokesForAction(a); 2973 if (pStrokes != null) { 2974 int rCount = 0; 2977 for (int counter = pStrokes.length - 1; counter >= 0; 2978 counter--) { 2979 if (isLocallyDefined(pStrokes[counter])) { 2980 pStrokes[counter] = null; 2981 rCount++; 2982 } 2983 } 2984 if (rCount > 0 && rCount < pStrokes.length) { 2985 if (keyStrokes == null) { 2986 keyStrokes = new Vector (); 2987 } 2988 for (int counter = pStrokes.length - 1; counter >= 0; 2989 counter--) { 2990 if (pStrokes[counter] != null) { 2991 keyStrokes.addElement(pStrokes[counter]); 2992 } 2993 } 2994 } 2995 else if (rCount == 0) { 2996 if (keyStrokes == null) { 2997 retValue = pStrokes; 2998 } 2999 else { 3000 retValue = new KeyStroke[keyStrokes.size() + 3001 pStrokes.length]; 3002 keyStrokes.copyInto(retValue); 3003 System.arraycopy(pStrokes, 0, retValue, 3004 keyStrokes.size(), pStrokes.length); 3005 keyStrokes = null; 3006 } 3007 } 3008 } 3009 } 3010 if (keyStrokes != null) { 3011 retValue = new KeyStroke[keyStrokes.size()]; 3012 keyStrokes.copyInto(retValue); 3013 } 3014 return retValue; 3015 } 3016 3017 public boolean isLocallyDefined(KeyStroke key) { 3018 return bindings.containsKey(key); 3019 } 3020 3021 public void addActionForKeyStroke(KeyStroke key, Action a) { 3022 bindings.put(key, a); 3023 } 3024 3025 public void removeKeyStrokeBinding(KeyStroke key) { 3026 bindings.remove(key); 3027 } 3028 3029 public void removeBindings() { 3030 bindings.clear(); 3031 } 3032 3033 public Keymap getResolveParent() { 3034 return parent; 3035 } 3036 3037 public void setResolveParent(Keymap parent) { 3038 this.parent = parent; 3039 } 3040 3041 3045 public String toString() { 3046 return "Keymap[" + nm + "]" + bindings; 3047 } 3048 3049 String nm; 3050 Keymap parent; 3051 Hashtable bindings; 3052 Action defaultAction; 3053 } 3054 3055 3056 3071 static class KeymapWrapper extends InputMap { 3072 static final Object DefaultActionKey = new Object (); 3073 3074 private Keymap keymap; 3075 3076 KeymapWrapper(Keymap keymap) { 3077 this.keymap = keymap; 3078 } 3079 3080 public KeyStroke[] keys() { 3081 KeyStroke[] sKeys = super.keys(); 3082 KeyStroke[] keymapKeys = keymap.getBoundKeyStrokes(); 3083 int sCount = (sKeys == null) ? 0 : sKeys.length; 3084 int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length; 3085 if (sCount == 0) { 3086 return keymapKeys; 3087 } 3088 if (keymapCount == 0) { 3089 return sKeys; 3090 } 3091 KeyStroke[] retValue = new KeyStroke[sCount + keymapCount]; 3092 System.arraycopy(sKeys, 0, retValue, 0, sCount); 3094 System.arraycopy(keymapKeys, 0, retValue, sCount, keymapCount); 3095 return retValue; 3096 } 3097 3098 public int size() { 3099 KeyStroke[] keymapStrokes = keymap.getBoundKeyStrokes(); 3101 int keymapCount = (keymapStrokes == null) ? 0: 3102 keymapStrokes.length; 3103 return super.size() + keymapCount; 3104 } 3105 3106 public Object get(KeyStroke keyStroke) { 3107 Object retValue = keymap.getAction(keyStroke); 3108 if (retValue == null) { 3109 retValue = super.get(keyStroke); 3110 if (retValue == null && 3111 keyStroke.getKeyChar() != KeyEvent.CHAR_UNDEFINED && 3112 keymap.getDefaultAction() != null) { 3113 retValue = DefaultActionKey; 3116 } 3117 } 3118 return retValue; 3119 } 3120 } 3121 3122 3123 3129 static class KeymapActionMap extends ActionMap { 3130 private Keymap keymap; 3131 3132 KeymapActionMap(Keymap keymap) { 3133 this.keymap = keymap; 3134 } 3135 3136 public Object [] keys() { 3137 Object [] sKeys = super.keys(); 3138 Object [] keymapKeys = keymap.getBoundActions(); 3139 int sCount = (sKeys == null) ? 0 : sKeys.length; 3140 int keymapCount = (keymapKeys == null) ? 0 : keymapKeys.length; 3141 boolean hasDefault = (keymap.getDefaultAction() != null); 3142 if (hasDefault) { 3143 keymapCount++; 3144 } 3145 if (sCount == 0) { 3146 if (hasDefault) { 3147 Object [] retValue = new Object [keymapCount]; 3148 if (keymapCount > 1) { 3149 System.arraycopy(keymapKeys, 0, retValue, 0, 3150 keymapCount - 1); 3151 } 3152 retValue[keymapCount - 1] = KeymapWrapper.DefaultActionKey; 3153 return retValue; 3154 } 3155 return keymapKeys; 3156 } 3157 if (keymapCount == 0) { 3158 return sKeys; 3159 } 3160 Object [] retValue = new Object [sCount + keymapCount]; 3161 System.arraycopy(sKeys, 0, retValue, 0, sCount); 3163 if (hasDefault) { 3164 if (keymapCount > 1) { 3165 System.arraycopy(keymapKeys, 0, retValue, sCount, 3166 keymapCount - 1); 3167 } 3168 retValue[sCount + keymapCount - 1] = KeymapWrapper. 3169 DefaultActionKey; 3170 } 3171 else { 3172 System.arraycopy(keymapKeys, 0, retValue, sCount, keymapCount); 3173 } 3174 return retValue; 3175 } 3176 3177 public int size() { 3178 Object [] actions = keymap.getBoundActions(); 3180 int keymapCount = (actions == null) ? 0 : actions.length; 3181 if (keymap.getDefaultAction() != null) { 3182 keymapCount++; 3183 } 3184 return super.size() + keymapCount; 3185 } 3186 3187 public Action get(Object key) { 3188 Action retValue = super.get(key); 3189 if (retValue == null) { 3190 if (key == KeymapWrapper.DefaultActionKey) { 3192 retValue = keymap.getDefaultAction(); 3193 } 3194 else if (key instanceof Action ) { 3195 retValue = (Action )key; 3199 } 3200 } 3201 return retValue; 3202 } 3203 } 3204 3205 private static final Object FOCUSED_COMPONENT = 3206 new StringBuilder ("JTextComponent_FocusedComponent"); 3207 3208 3213 public static final String DEFAULT_KEYMAP = "default"; 3214 3215 3220 static class MutableCaretEvent extends CaretEvent implements ChangeListener, FocusListener, MouseListener { 3221 3222 MutableCaretEvent(JTextComponent c) { 3223 super(c); 3224 } 3225 3226 final void fire() { 3227 JTextComponent c = (JTextComponent ) getSource(); 3228 if (c != null) { 3229 Caret caret = c.getCaret(); 3230 dot = caret.getDot(); 3231 mark = caret.getMark(); 3232 c.fireCaretUpdate(this); 3233 } 3234 } 3235 3236 public final String toString() { 3237 return "dot=" + dot + "," + "mark=" + mark; 3238 } 3239 3240 3242 public final int getDot() { 3243 return dot; 3244 } 3245 3246 public final int getMark() { 3247 return mark; 3248 } 3249 3250 3252 public final void stateChanged(ChangeEvent e) { 3253 if (! dragActive) { 3254 fire(); 3255 } 3256 } 3257 3258 public void focusGained(FocusEvent fe) { 3260 AppContext.getAppContext().put(FOCUSED_COMPONENT, 3261 fe.getSource()); 3262 } 3263 3264 public void focusLost(FocusEvent fe) { 3265 } 3266 3267 3269 3276 public final void mousePressed(MouseEvent e) { 3277 dragActive = true; 3278 } 3279 3280 3286 public final void mouseReleased(MouseEvent e) { 3287 dragActive = false; 3288 fire(); 3289 } 3290 3291 public final void mouseClicked(MouseEvent e) { 3292 } 3293 3294 public final void mouseEntered(MouseEvent e) { 3295 } 3296 3297 public final void mouseExited(MouseEvent e) { 3298 } 3299 3300 private boolean dragActive; 3301 private int dot; 3302 private int mark; 3303 } 3304 3305 protected void processInputMethodEvent(InputMethodEvent e) { 3312 super.processInputMethodEvent(e); 3314 3315 if (!e.isConsumed()) { 3316 if (! isEditable()) { 3317 return; 3318 } else { 3319 switch (e.getID()) { 3320 case InputMethodEvent.INPUT_METHOD_TEXT_CHANGED: 3321 replaceInputMethodText(e); 3322 3323 3325 case InputMethodEvent.CARET_POSITION_CHANGED: 3326 setInputMethodCaretPosition(e); 3327 break; 3328 } 3329 } 3330 3331 e.consume(); 3332 } 3333 } 3334 3335 public InputMethodRequests getInputMethodRequests() { 3339 if (inputMethodRequestsHandler == null) { 3340 inputMethodRequestsHandler = 3341 (InputMethodRequests )new InputMethodRequestsHandler(); 3342 Document doc = getDocument(); 3343 if (doc != null) { 3344 doc.addDocumentListener((DocumentListener)inputMethodRequestsHandler); 3345 } 3346 } 3347 3348 return inputMethodRequestsHandler; 3349 } 3350 3351 public void addInputMethodListener(InputMethodListener l) { 3355 super.addInputMethodListener(l); 3356 if (l != null) { 3357 needToSendKeyTypedEvent = false; 3358 checkedInputOverride = true; 3359 } 3360 } 3361 3362 3363 class InputMethodRequestsHandler implements InputMethodRequests , DocumentListener { 3367 3368 3370 public AttributedCharacterIterator cancelLatestCommittedText( 3371 Attribute [] attributes) { 3372 Document doc = getDocument(); 3373 if ((doc != null) && (latestCommittedTextStart != null) 3374 && (!latestCommittedTextStart.equals(latestCommittedTextEnd))) { 3375 try { 3376 int startIndex = latestCommittedTextStart.getOffset(); 3377 int endIndex = latestCommittedTextEnd.getOffset(); 3378 String latestCommittedText = 3379 doc.getText(startIndex, endIndex - startIndex); 3380 doc.remove(startIndex, endIndex - startIndex); 3381 return new AttributedString(latestCommittedText).getIterator(); 3382 } catch (BadLocationException ble) {} 3383 } 3384 return null; 3385 } 3386 3387 public AttributedCharacterIterator getCommittedText(int beginIndex, 3388 int endIndex, Attribute [] attributes) { 3389 int composedStartIndex = 0; 3390 int composedEndIndex = 0; 3391 if (composedTextExists()) { 3392 composedStartIndex = composedTextStart.getOffset(); 3393 composedEndIndex = composedTextEnd.getOffset(); 3394 } 3395 3396 String committed; 3397 try { 3398 if (beginIndex < composedStartIndex) { 3399 if (endIndex <= composedStartIndex) { 3400 committed = getText(beginIndex, endIndex - beginIndex); 3401 } else { 3402 int firstPartLength = composedStartIndex - beginIndex; 3403 committed = getText(beginIndex, firstPartLength) + 3404 getText(composedEndIndex, endIndex - beginIndex - firstPartLength); 3405 } 3406 } else { 3407 committed = getText(beginIndex + (composedEndIndex - composedStartIndex), 3408 endIndex - beginIndex); 3409 } 3410 } catch (BadLocationException ble) { 3411 throw new IllegalArgumentException ("Invalid range"); 3412 } 3413 return new AttributedString(committed).getIterator(); 3414 } 3415 3416 public int getCommittedTextLength() { 3417 Document doc = getDocument(); 3418 int length = 0; 3419 if (doc != null) { 3420 length = doc.getLength(); 3421 if (composedTextContent != null) { 3422 if (composedTextEnd == null 3423 || composedTextStart == null) { 3424 3431 length -= composedTextContent.length(); 3432 } else { 3433 length -= composedTextEnd.getOffset() - 3434 composedTextStart.getOffset(); 3435 } 3436 } 3437 } 3438 return length; 3439 } 3440 3441 public int getInsertPositionOffset() { 3442 int composedStartIndex = 0; 3443 int composedEndIndex = 0; 3444 if (composedTextExists()) { 3445 composedStartIndex = composedTextStart.getOffset(); 3446 composedEndIndex = composedTextEnd.getOffset(); 3447 } 3448 int caretIndex = getCaretPosition(); 3449 3450 if (caretIndex < composedStartIndex) { 3451 return caretIndex; 3452 } else if (caretIndex < composedEndIndex) { 3453 return composedStartIndex; 3454 } else { 3455 return caretIndex - (composedEndIndex - composedStartIndex); 3456 } 3457 } 3458 3459 public TextHitInfo getLocationOffset(int x, int y) { 3460 if (composedTextAttribute == null) { 3461 return null; 3462 } else { 3463 Point p = getLocationOnScreen(); 3464 p.x = x - p.x; 3465 p.y = y - p.y; 3466 int pos = viewToModel(p); 3467 if ((pos >= composedTextStart.getOffset()) && 3468 (pos <= composedTextEnd.getOffset())) { 3469 return TextHitInfo.leading(pos - composedTextStart.getOffset()); 3470 } else { 3471 return null; 3472 } 3473 } 3474 } 3475 3476 public Rectangle getTextLocation(TextHitInfo offset) { 3477 Rectangle r; 3478 3479 try { 3480 r = modelToView(getCaretPosition()); 3481 if (r != null) { 3482 Point p = getLocationOnScreen(); 3483 r.translate(p.x, p.y); 3484 } 3485 } catch (BadLocationException ble) { 3486 r = null; 3487 } 3488 3489 if (r == null) 3490 r = new Rectangle(); 3491 3492 return r; 3493 } 3494 3495 public AttributedCharacterIterator getSelectedText( 3496 Attribute [] attributes) { 3497 String selection = JTextComponent.this.getSelectedText(); 3498 if (selection != null) { 3499 return new AttributedString(selection).getIterator(); 3500 } else { 3501 return null; 3502 } 3503 } 3504 3505 3507 public void changedUpdate(DocumentEvent e) { 3508 latestCommittedTextStart = latestCommittedTextEnd = null; 3509 } 3510 3511 public void insertUpdate(DocumentEvent e) { 3512 latestCommittedTextStart = latestCommittedTextEnd = null; 3513 } 3514 3515 public void removeUpdate(DocumentEvent e) { 3516 latestCommittedTextStart = latestCommittedTextEnd = null; 3517 } 3518 } 3519 3520 private void replaceInputMethodText(InputMethodEvent e) { 3526 int commitCount = e.getCommittedCharacterCount(); 3527 AttributedCharacterIterator text = e.getText(); 3528 int composedTextIndex; 3529 3530 Document doc = getDocument(); 3532 if (composedTextExists()) { 3533 try { 3534 doc.remove(composedTextStart.getOffset(), 3535 composedTextEnd.getOffset() - 3536 composedTextStart.getOffset()); 3537 } catch (BadLocationException ble) {} 3538 composedTextStart = composedTextEnd = null; 3539 composedTextAttribute = null; 3540 composedTextContent = null; 3541 } 3542 3543 if (text != null) { 3544 text.first(); 3545 int committedTextStartIndex = 0; 3546 int committedTextEndIndex = 0; 3547 3548 if (commitCount > 0) { 3550 committedTextStartIndex = caret.getDot(); 3552 3553 if (shouldSynthensizeKeyEvents()) { 3556 for (char c = text.current(); commitCount > 0; 3557 c = text.next(), commitCount--) { 3558 KeyEvent ke = new KeyEvent(this, KeyEvent.KEY_TYPED, 3559 EventQueue.getMostRecentEventTime(), 3560 0, KeyEvent.VK_UNDEFINED, c); 3561 processKeyEvent(ke); 3562 } 3563 } else { 3564 StringBuffer strBuf = new StringBuffer (); 3565 for (char c = text.current(); commitCount > 0; 3566 c = text.next(), commitCount--) { 3567 strBuf.append(c); 3568 } 3569 3570 mapCommittedTextToAction(new String (strBuf)); 3572 } 3573 3574 committedTextEndIndex = caret.getDot(); 3576 } 3577 3578 composedTextIndex = text.getIndex(); 3580 if (composedTextIndex < text.getEndIndex()) { 3581 createComposedTextAttribute(composedTextIndex, text); 3582 try { 3583 replaceSelection(null); 3584 doc.insertString(caret.getDot(), composedTextContent, 3585 composedTextAttribute); 3586 composedTextStart = doc.createPosition(caret.getDot() - 3587 composedTextContent.length()); 3588 composedTextEnd = doc.createPosition(caret.getDot()); 3589 } catch (BadLocationException ble) { 3590 composedTextStart = composedTextEnd = null; 3591 composedTextAttribute = null; 3592 composedTextContent = null; 3593 } 3594 } 3595 3596 if (committedTextStartIndex != committedTextEndIndex) { 3598 try { 3599 latestCommittedTextStart = doc. 3600 createPosition(committedTextStartIndex); 3601 latestCommittedTextEnd = doc. 3602 createPosition(committedTextEndIndex); 3603 } catch (BadLocationException ble) { 3604 latestCommittedTextStart = 3605 latestCommittedTextEnd = null; 3606 } 3607 } else { 3608 latestCommittedTextStart = 3609 latestCommittedTextEnd = null; 3610 } 3611 } 3612 } 3613 3614 private void createComposedTextAttribute(int composedIndex, 3615 AttributedCharacterIterator text) { 3616 Document doc = getDocument(); 3617 StringBuffer strBuf = new StringBuffer (); 3618 3619 for (char c = text.setIndex(composedIndex); 3621 c != CharacterIterator.DONE; c = text.next()) { 3622 strBuf.append(c); 3623 } 3624 3625 composedTextContent = new String (strBuf); 3626 composedTextAttribute = new SimpleAttributeSet (); 3627 composedTextAttribute.addAttribute(StyleConstants.ComposedTextAttribute, 3628 new AttributedString(text, composedIndex, text.getEndIndex())); 3629 } 3630 3631 private boolean saveComposedText(int pos) { 3632 if (composedTextExists()) { 3633 int start = composedTextStart.getOffset(); 3634 int len = composedTextEnd.getOffset() - 3635 composedTextStart.getOffset(); 3636 if (pos >= start && pos <= start + len) { 3637 try { 3638 getDocument().remove(start, len); 3639 return true; 3640 } catch (BadLocationException ble) {} 3641 } 3642 } 3643 return false; 3644 } 3645 3646 private void restoreComposedText() { 3647 Document doc = getDocument(); 3648 try { 3649 doc.insertString(caret.getDot(), 3650 composedTextContent, 3651 composedTextAttribute); 3652 composedTextStart = doc.createPosition(caret.getDot() - 3653 composedTextContent.length()); 3654 composedTextEnd = doc.createPosition(caret.getDot()); 3655 } catch (BadLocationException ble) {} 3656 } 3657 3658 private void mapCommittedTextToAction(String committedText) { 3664 Keymap binding = getKeymap(); 3665 if (binding != null) { 3666 Action a = null; 3667 if (committedText.length() == 1) { 3668 KeyStroke k = KeyStroke.getKeyStroke(committedText.charAt(0)); 3669 a = binding.getAction(k); 3670 } 3671 3672 if (a == null) { 3673 a = binding.getDefaultAction(); 3674 } 3675 3676 if (a != null) { 3677 ActionEvent ae = 3678 new ActionEvent(this, ActionEvent.ACTION_PERFORMED, 3679 committedText, 3680 EventQueue.getMostRecentEventTime(), 3681 getCurrentEventModifiers()); 3682 a.actionPerformed(ae); 3683 } 3684 } 3685 } 3686 3687 private void setInputMethodCaretPosition(InputMethodEvent e) { 3692 int dot; 3693 3694 if (composedTextExists()) { 3695 dot = composedTextStart.getOffset(); 3696 if (!(caret instanceof ComposedTextCaret)) { 3697 if (composedTextCaret == null) { 3698 composedTextCaret = new ComposedTextCaret(); 3699 } 3700 originalCaret = caret; 3701 exchangeCaret(originalCaret, composedTextCaret); 3703 } 3704 3705 TextHitInfo caretPos = e.getCaret(); 3706 if (caretPos != null) { 3707 int index = caretPos.getInsertionIndex(); 3708 dot += index; 3709 if (index == 0) { 3710 try { 3713 Rectangle d = modelToView(dot); 3714 Rectangle end = modelToView(composedTextEnd.getOffset()); 3715 Rectangle b = getBounds(); 3716 d.x += Math.min(end.x - d.x, b.width); 3717 scrollRectToVisible(d); 3718 } catch (BadLocationException ble) {} 3719 } 3720 } 3721 caret.setDot(dot); 3722 } else if (caret instanceof ComposedTextCaret) { 3723 dot = caret.getDot(); 3724 exchangeCaret(caret, originalCaret); 3726 caret.setDot(dot); 3727 } 3728 } 3729 3730 private void exchangeCaret(Caret oldCaret, Caret newCaret) { 3731 int blinkRate = oldCaret.getBlinkRate(); 3732 setCaret(newCaret); 3733 caret.setBlinkRate(blinkRate); 3734 caret.setVisible(hasFocus()); 3735 } 3736 3737 3740 private boolean shouldSynthensizeKeyEvents() { 3741 if (!checkedInputOverride) { 3742 checkedInputOverride = true; 3743 needToSendKeyTypedEvent = 3744 !isProcessInputMethodEventOverridden(); 3745 } 3746 return needToSendKeyTypedEvent; 3747 } 3748 3749 private boolean isProcessInputMethodEventOverridden() { 3755 if (overrideMap == null) { 3756 overrideMap = Collections.synchronizedMap(new HashMap ()); 3757 } 3758 Boolean retValue = (Boolean )overrideMap.get(getClass().getName()); 3759 3760 if (retValue != null) { 3761 return retValue.booleanValue(); 3762 } 3763 Boolean ret = (Boolean )AccessController.doPrivileged(new 3764 PrivilegedAction () { 3765 public Object run() { 3766 return isProcessInputMethodEventOverridden( 3767 JTextComponent.this.getClass()); 3768 } 3769 }); 3770 3771 return ret.booleanValue(); 3772 } 3773 3774 boolean composedTextExists() { 3778 return (composedTextStart != null); 3779 } 3780 3781 class ComposedTextCaret extends DefaultCaret implements Serializable { 3785 Color bg; 3786 3787 public void install(JTextComponent c) { 3791 super.install(c); 3792 3793 Document doc = c.getDocument(); 3794 if (doc instanceof StyledDocument ) { 3795 StyledDocument sDoc = (StyledDocument )doc; 3796 Element elem = sDoc.getCharacterElement(c.composedTextStart.getOffset()); 3797 AttributeSet attr = elem.getAttributes(); 3798 bg = sDoc.getBackground(attr); 3799 } 3800 3801 if (bg == null) { 3802 bg = c.getBackground(); 3803 } 3804 } 3805 3806 public void paint(Graphics g) { 3810 if(isVisible()) { 3811 try { 3812 Rectangle r = component.modelToView(getDot()); 3813 g.setXORMode(bg); 3814 g.drawLine(r.x, r.y, r.x, r.y + r.height - 1); 3815 g.setPaintMode(); 3816 } catch (BadLocationException e) { 3817 } 3820 } 3821 } 3822 3823 protected void positionCaret(MouseEvent me) { 3828 JTextComponent host = component; 3829 Point pt = new Point(me.getX(), me.getY()); 3830 int offset = host.viewToModel(pt); 3831 int composedStartIndex = host.composedTextStart.getOffset(); 3832 if ((offset < composedStartIndex) || 3833 (offset > composedTextEnd.getOffset())) { 3834 try { 3835 Position newPos = host.getDocument().createPosition(offset); 3837 host.getInputContext().endComposition(); 3838 3839 EventQueue.invokeLater(new DoSetCaretPosition(host, newPos)); 3842 } catch (BadLocationException ble) { 3843 System.err.println(ble); 3844 } 3845 } else { 3846 super.positionCaret(me); 3848 } 3849 } 3850 } 3851 3852 private class DoSetCaretPosition implements Runnable { 3856 JTextComponent host; 3857 Position newPos; 3858 3859 DoSetCaretPosition(JTextComponent host, Position newPos) { 3860 this.host = host; 3861 this.newPos = newPos; 3862 } 3863 3864 public void run() { 3865 host.setCaretPosition(newPos.getOffset()); 3866 } 3867 } 3868} 3869 3870 3871 | Popular Tags |