Frames | No Frames |
1: /* DefaultCaret.java -- 2: Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: package javax.swing.text; 39: 40: import java.awt.Graphics; 41: import java.awt.Point; 42: import java.awt.Rectangle; 43: import java.awt.event.ActionEvent; 44: import java.awt.event.ActionListener; 45: import java.awt.event.FocusEvent; 46: import java.awt.event.FocusListener; 47: import java.awt.event.MouseEvent; 48: import java.awt.event.MouseListener; 49: import java.awt.event.MouseMotionListener; 50: import java.beans.PropertyChangeEvent; 51: import java.beans.PropertyChangeListener; 52: import java.util.EventListener; 53: 54: import javax.swing.JComponent; 55: import javax.swing.SwingUtilities; 56: import javax.swing.Timer; 57: import javax.swing.event.ChangeEvent; 58: import javax.swing.event.ChangeListener; 59: import javax.swing.event.DocumentEvent; 60: import javax.swing.event.DocumentListener; 61: import javax.swing.event.EventListenerList; 62: 63: /** 64: * The default implementation of the {@link Caret} interface. 65: * 66: * @author orgininal author unknown 67: * @author Roman Kennke (roman@kennke.org) 68: */ 69: public class DefaultCaret extends Rectangle 70: implements Caret, FocusListener, MouseListener, MouseMotionListener 71: { 72: 73: /** 74: * Controls the blinking of the caret. 75: * 76: * @author Roman Kennke (kennke@aicas.com) 77: * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) 78: */ 79: private class BlinkTimerListener implements ActionListener 80: { 81: /** 82: * Forces the next event to be ignored. The next event should be ignored 83: * if we force the caret to appear. We do not know how long will it take 84: * to fire the comming event; this may be near immediately. Better to leave 85: * the caret visible one iteration longer. 86: */ 87: boolean ignoreNextEvent; 88: 89: /** 90: * Receives notification when the blink timer fires and updates the visible 91: * state of the caret. 92: * 93: * @param event the action event 94: */ 95: public void actionPerformed(ActionEvent event) 96: { 97: if (ignoreNextEvent) 98: ignoreNextEvent = false; 99: else 100: { 101: visible = !visible; 102: repaint(); 103: } 104: } 105: } 106: 107: /** 108: * Listens for changes in the text component's document and updates the 109: * caret accordingly. 110: * 111: * @author Roman Kennke (kennke@aicas.com) 112: */ 113: private class DocumentHandler implements DocumentListener 114: { 115: /** 116: * Receives notification that some text attributes have changed. No action 117: * is taken here. 118: * 119: * @param event the document event 120: */ 121: public void changedUpdate(DocumentEvent event) 122: { 123: // Nothing to do here. 124: } 125: 126: /** 127: * Receives notification that some text has been inserted from the text 128: * component. The caret is moved forward accordingly. 129: * 130: * @param event the document event 131: */ 132: public void insertUpdate(DocumentEvent event) 133: { 134: if (policy == ALWAYS_UPDATE || 135: (SwingUtilities.isEventDispatchThread() && 136: policy == UPDATE_WHEN_ON_EDT)) 137: { 138: int dot = getDot(); 139: setDot(dot + event.getLength()); 140: } 141: } 142: 143: /** 144: * Receives notification that some text has been removed into the text 145: * component. The caret is moved backwards accordingly. 146: * 147: * @param event the document event 148: */ 149: public void removeUpdate(DocumentEvent event) 150: { 151: if (policy == ALWAYS_UPDATE || 152: (SwingUtilities.isEventDispatchThread() && 153: policy == UPDATE_WHEN_ON_EDT)) 154: { 155: int dot = getDot(); 156: setDot(dot - event.getLength()); 157: } 158: else if (policy == NEVER_UPDATE) 159: { 160: int docLength = event.getDocument().getLength(); 161: if (getDot() > docLength) 162: setDot(docLength); 163: } 164: } 165: } 166: 167: /** 168: * Listens for property changes on the text document. This is used to add and 169: * remove our document listener, if the document of the text component has 170: * changed. 171: * 172: * @author Roman Kennke (kennke@aicas.com) 173: */ 174: private class PropertyChangeHandler implements PropertyChangeListener 175: { 176: 177: /** 178: * Receives notification when a property has changed on the text component. 179: * This adds/removes our document listener from the text component's 180: * document when the document changes. 181: * 182: * @param e the property change event 183: */ 184: public void propertyChange(PropertyChangeEvent e) 185: { 186: if (e.getPropertyName().equals("document")) 187: { 188: Document oldDoc = (Document) e.getOldValue(); 189: oldDoc.removeDocumentListener(documentListener); 190: Document newDoc = (Document) e.getNewValue(); 191: newDoc.addDocumentListener(documentListener); 192: } 193: } 194: 195: } 196: 197: /** The serialization UID (compatible with JDK1.5). */ 198: private static final long serialVersionUID = 4325555698756477346L; 199: 200: /** 201: * Indicates the Caret position should always be updated after Document 202: * changes even if the updates are not performed on the Event Dispatching 203: * thread. 204: * 205: * @since 1.5 206: */ 207: public static final int ALWAYS_UPDATE = 2; 208: 209: /** 210: * Indicates the Caret position should not be changed unless the Document 211: * length becomes less than the Caret position, in which case the Caret 212: * is moved to the end of the Document. 213: * 214: * @since 1.5 215: */ 216: public static final int NEVER_UPDATE = 1; 217: 218: /** 219: * Indicates the Caret position should be updated only if Document changes 220: * are made on the Event Dispatcher thread. 221: * 222: * @since 1.5 223: */ 224: public static final int UPDATE_WHEN_ON_EDT = 0; 225: 226: /** Keeps track of the current update policy **/ 227: int policy = UPDATE_WHEN_ON_EDT; 228: 229: /** 230: * The <code>ChangeEvent</code> that is fired by {@link #fireStateChanged()}. 231: */ 232: protected ChangeEvent changeEvent = new ChangeEvent(this); 233: 234: /** 235: * Stores all registered event listeners. 236: */ 237: protected EventListenerList listenerList = new EventListenerList(); 238: 239: /** 240: * Our document listener. 241: */ 242: DocumentListener documentListener; 243: 244: /** 245: * Our property listener. 246: */ 247: PropertyChangeListener propertyChangeListener; 248: 249: /** 250: * The text component in which this caret is installed. 251: */ 252: private JTextComponent textComponent; 253: 254: /** 255: * Indicates if the selection should be visible or not. 256: */ 257: private boolean selectionVisible = true; 258: 259: /** 260: * The blink rate of this <code>Caret</code>. 261: */ 262: private int blinkRate = 500; 263: 264: /** 265: * The current dot position. 266: */ 267: private int dot = 0; 268: 269: /** 270: * The current mark position. 271: */ 272: private int mark = 0; 273: 274: /** 275: * The current visual caret position. 276: */ 277: private Point magicCaretPosition = null; 278: 279: /** 280: * Indicates if this <code>Caret</code> is currently visible or not. This is 281: * package private to avoid an accessor method. 282: */ 283: boolean visible = false; 284: 285: /** 286: * The current highlight entry. 287: */ 288: private Object highlightEntry; 289: 290: private Timer blinkTimer; 291: 292: private BlinkTimerListener blinkListener; 293: 294: /** 295: * Creates a new <code>DefaultCaret</code> instance. 296: */ 297: public DefaultCaret() 298: { 299: // Nothing to do here. 300: } 301: 302: /** 303: * Sets the Caret update policy. 304: * 305: * @param policy the new policy. Valid values are: 306: * ALWAYS_UPDATE: always update the Caret position, even when Document 307: * updates don't occur on the Event Dispatcher thread. 308: * NEVER_UPDATE: don't update the Caret position unless the Document 309: * length becomes less than the Caret position (then update the 310: * Caret to the end of the Document). 311: * UPDATE_WHEN_ON_EDT: update the Caret position when the 312: * Document updates occur on the Event Dispatcher thread. This is the 313: * default. 314: * 315: * @since 1.5 316: * @throws IllegalArgumentException if policy is not one of the above. 317: */ 318: public void setUpdatePolicy (int policy) 319: { 320: if (policy != ALWAYS_UPDATE && policy != NEVER_UPDATE 321: && policy != UPDATE_WHEN_ON_EDT) 322: throw new 323: IllegalArgumentException 324: ("policy must be ALWAYS_UPDATE, NEVER__UPDATE, or UPDATE_WHEN_ON_EDT"); 325: this.policy = policy; 326: } 327: 328: /** 329: * Gets the caret update policy. 330: * 331: * @return the caret update policy. 332: * @since 1.5 333: */ 334: public int getUpdatePolicy () 335: { 336: return policy; 337: } 338: 339: /** 340: * Moves the caret position when the mouse is dragged over the text 341: * component, modifying the selection accordingly. 342: * 343: * @param event the <code>MouseEvent</code> describing the drag operation 344: */ 345: public void mouseDragged(MouseEvent event) 346: { 347: moveCaret(event); 348: } 349: 350: /** 351: * Indicates a mouse movement over the text component. Does nothing here. 352: * 353: * @param event the <code>MouseEvent</code> describing the mouse operation 354: */ 355: public void mouseMoved(MouseEvent event) 356: { 357: // Nothing to do here. 358: } 359: 360: /** 361: * When the click is received from Button 1 then the following actions 362: * are performed here: 363: * 364: * <ul> 365: * <li>If we receive a double click, the caret position (dot) is set 366: * to the position associated to the mouse click and the word at 367: * this location is selected.</li> 368: * <li>If we receive a triple click, the caret position (dot) is set 369: * to the position associated to the mouse click and the line at 370: * this location is selected.</li> 371: * </ul> 372: * 373: * @param event the <code>MouseEvent</code> describing the click operation 374: */ 375: public void mouseClicked(MouseEvent event) 376: { 377: // TODO: Implement double- and triple-click behaviour here. 378: } 379: 380: /** 381: * Indicates that the mouse has entered the text component. Nothing is done 382: * here. 383: * 384: * @param event the <code>MouseEvent</code> describing the mouse operation 385: */ 386: public void mouseEntered(MouseEvent event) 387: { 388: // Nothing to do here. 389: } 390: 391: /** 392: * Indicates that the mouse has exited the text component. Nothing is done 393: * here. 394: * 395: * @param event the <code>MouseEvent</code> describing the mouse operation 396: */ 397: public void mouseExited(MouseEvent event) 398: { 399: // Nothing to do here. 400: } 401: 402: /** 403: * If the button 1 is pressed, the caret position is updated to the 404: * position of the mouse click and the text component requests the input 405: * focus if it is enabled. If the SHIFT key is held down, the caret will 406: * be moved, which might select the text between the old and new location. 407: * 408: * @param event the <code>MouseEvent</code> describing the press operation 409: */ 410: public void mousePressed(MouseEvent event) 411: { 412: positionCaret(event); 413: } 414: 415: /** 416: * Indicates that a mouse button has been released on the text component. 417: * Nothing is done here. 418: * 419: * @param event the <code>MouseEvent</code> describing the mouse operation 420: */ 421: public void mouseReleased(MouseEvent event) 422: { 423: // Nothing to do here. 424: } 425: 426: /** 427: * Sets the caret to <code>visible</code> if the text component is editable. 428: * 429: * @param event the <code>FocusEvent</code> 430: */ 431: public void focusGained(FocusEvent event) 432: { 433: setVisible(true); 434: } 435: 436: /** 437: * Sets the caret to <code>invisible</code>. 438: * 439: * @param event the <code>FocusEvent</code> 440: */ 441: public void focusLost(FocusEvent event) 442: { 443: if (event.isTemporary() == false) 444: setVisible(false); 445: } 446: 447: /** 448: * Moves the caret to the position specified in the <code>MouseEvent</code>. 449: * This will cause a selection if the dot and mark are different. 450: * 451: * @param event the <code>MouseEvent</code> from which to fetch the position 452: */ 453: protected void moveCaret(MouseEvent event) 454: { 455: int newDot = getComponent().viewToModel(event.getPoint()); 456: moveDot(newDot); 457: } 458: 459: /** 460: * Repositions the caret to the position specified in the 461: * <code>MouseEvent</code>. 462: * 463: * @param event the <code>MouseEvent</code> from which to fetch the position 464: */ 465: protected void positionCaret(MouseEvent event) 466: { 467: int newDot = getComponent().viewToModel(event.getPoint()); 468: setDot(newDot); 469: } 470: 471: /** 472: * Deinstalls this <code>Caret</code> from the specified 473: * <code>JTextComponent</code>. This removes any listeners that have been 474: * registered by this <code>Caret</code>. 475: * 476: * @param c the text component from which to install this caret 477: */ 478: public void deinstall(JTextComponent c) 479: { 480: textComponent.removeFocusListener(this); 481: textComponent.removeMouseListener(this); 482: textComponent.removeMouseMotionListener(this); 483: textComponent.getDocument().removeDocumentListener(documentListener); 484: documentListener = null; 485: textComponent.removePropertyChangeListener(propertyChangeListener); 486: propertyChangeListener = null; 487: textComponent = null; 488: 489: // Deinstall blink timer if present. 490: if (blinkTimer != null) 491: blinkTimer.stop(); 492: blinkTimer = null; 493: } 494: 495: /** 496: * Installs this <code>Caret</code> on the specified 497: * <code>JTextComponent</code>. This registers a couple of listeners 498: * on the text component. 499: * 500: * @param c the text component on which to install this caret 501: */ 502: public void install(JTextComponent c) 503: { 504: textComponent = c; 505: textComponent.addFocusListener(this); 506: textComponent.addMouseListener(this); 507: textComponent.addMouseMotionListener(this); 508: propertyChangeListener = new PropertyChangeHandler(); 509: textComponent.addPropertyChangeListener(propertyChangeListener); 510: documentListener = new DocumentHandler(); 511: textComponent.getDocument().addDocumentListener(documentListener); 512: 513: repaint(); 514: } 515: 516: /** 517: * Sets the current visual position of this <code>Caret</code>. 518: * 519: * @param p the Point to use for the saved location. May be <code>null</code> 520: * to indicate that there is no visual location 521: */ 522: public void setMagicCaretPosition(Point p) 523: { 524: magicCaretPosition = p; 525: } 526: 527: /** 528: * Returns the current visual position of this <code>Caret</code>. 529: * 530: * @return the current visual position of this <code>Caret</code> 531: * 532: * @see #setMagicCaretPosition 533: */ 534: public Point getMagicCaretPosition() 535: { 536: return magicCaretPosition; 537: } 538: 539: /** 540: * Returns the current position of the <code>mark</code>. The 541: * <code>mark</code> marks the location in the <code>Document</code> that 542: * is the end of a selection. If there is no selection, the <code>mark</code> 543: * is the same as the <code>dot</code>. 544: * 545: * @return the current position of the mark 546: */ 547: public int getMark() 548: { 549: return mark; 550: } 551: 552: private void handleHighlight() 553: { 554: Highlighter highlighter = textComponent.getHighlighter(); 555: 556: if (highlighter == null) 557: return; 558: 559: int p0 = Math.min(dot, mark); 560: int p1 = Math.max(dot, mark); 561: 562: if (selectionVisible && p0 != p1) 563: { 564: try 565: { 566: if (highlightEntry == null) 567: highlightEntry = highlighter.addHighlight(p0, p1, getSelectionPainter()); 568: else 569: highlighter.changeHighlight(highlightEntry, p0, p1); 570: } 571: catch (BadLocationException e) 572: { 573: // This should never happen. 574: throw new InternalError(); 575: } 576: } 577: else 578: { 579: if (highlightEntry != null) 580: { 581: highlighter.removeHighlight(highlightEntry); 582: highlightEntry = null; 583: } 584: } 585: } 586: 587: /** 588: * Sets the visiblity state of the selection. 589: * 590: * @param v <code>true</code> if the selection should be visible, 591: * <code>false</code> otherwise 592: */ 593: public void setSelectionVisible(boolean v) 594: { 595: if (selectionVisible == v) 596: return; 597: 598: selectionVisible = v; 599: handleHighlight(); 600: repaint(); 601: } 602: 603: /** 604: * Returns <code>true</code> if the selection is currently visible, 605: * <code>false</code> otherwise. 606: * 607: * @return <code>true</code> if the selection is currently visible, 608: * <code>false</code> otherwise 609: */ 610: public boolean isSelectionVisible() 611: { 612: return selectionVisible; 613: } 614: 615: /** 616: * Causes the <code>Caret</code> to repaint itself. 617: */ 618: protected final void repaint() 619: { 620: getComponent().repaint(x, y, width, height); 621: } 622: 623: /** 624: * Paints this <code>Caret</code> using the specified <code>Graphics</code> 625: * context. 626: * 627: * @param g the graphics context to use 628: */ 629: public void paint(Graphics g) 630: { 631: JTextComponent comp = getComponent(); 632: if (comp == null) 633: return; 634: 635: int dot = getDot(); 636: Rectangle rect = null; 637: 638: try 639: { 640: rect = textComponent.modelToView(dot); 641: } 642: catch (BadLocationException e) 643: { 644: assert false : "Unexpected bad caret location: " + dot; 645: return; 646: } 647: 648: if (rect == null) 649: return; 650: 651: // Check if paint has possibly been called directly, without a previous 652: // call to damage(). In this case we need to do some cleanup first. 653: if ((x != rect.x) || (y != rect.y)) 654: { 655: repaint(); // Erase previous location of caret. 656: x = rect.x; 657: y = rect.y; 658: width = 1; 659: height = rect.height; 660: } 661: 662: // Now draw the caret on the new position if visible. 663: if (visible) 664: { 665: g.setColor(textComponent.getCaretColor()); 666: g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height); 667: } 668: } 669: 670: /** 671: * Returns all registered event listeners of the specified type. 672: * 673: * @param listenerType the type of listener to return 674: * 675: * @return all registered event listeners of the specified type 676: */ 677: public EventListener[] getListeners(Class listenerType) 678: { 679: return listenerList.getListeners(listenerType); 680: } 681: 682: /** 683: * Registers a {@link ChangeListener} that is notified whenever that state 684: * of this <code>Caret</code> changes. 685: * 686: * @param listener the listener to register to this caret 687: */ 688: public void addChangeListener(ChangeListener listener) 689: { 690: listenerList.add(ChangeListener.class, listener); 691: } 692: 693: /** 694: * Removes a {@link ChangeListener} from the list of registered listeners. 695: * 696: * @param listener the listener to remove 697: */ 698: public void removeChangeListener(ChangeListener listener) 699: { 700: listenerList.remove(ChangeListener.class, listener); 701: } 702: 703: /** 704: * Returns all registered {@link ChangeListener}s of this <code>Caret</code>. 705: * 706: * @return all registered {@link ChangeListener}s of this <code>Caret</code> 707: */ 708: public ChangeListener[] getChangeListeners() 709: { 710: return (ChangeListener[]) getListeners(ChangeListener.class); 711: } 712: 713: /** 714: * Notifies all registered {@link ChangeListener}s that the state 715: * of this <code>Caret</code> has changed. 716: */ 717: protected void fireStateChanged() 718: { 719: ChangeListener[] listeners = getChangeListeners(); 720: 721: for (int index = 0; index < listeners.length; ++index) 722: listeners[index].stateChanged(changeEvent); 723: } 724: 725: /** 726: * Returns the <code>JTextComponent</code> on which this <code>Caret</code> 727: * is installed. 728: * 729: * @return the <code>JTextComponent</code> on which this <code>Caret</code> 730: * is installed 731: */ 732: protected final JTextComponent getComponent() 733: { 734: return textComponent; 735: } 736: 737: /** 738: * Returns the blink rate of this <code>Caret</code> in milliseconds. 739: * A value of <code>0</code> means that the caret does not blink. 740: * 741: * @return the blink rate of this <code>Caret</code> or <code>0</code> if 742: * this caret does not blink 743: */ 744: public int getBlinkRate() 745: { 746: return blinkRate; 747: } 748: 749: /** 750: * Sets the blink rate of this <code>Caret</code> in milliseconds. 751: * A value of <code>0</code> means that the caret does not blink. 752: * 753: * @param rate the new blink rate to set 754: */ 755: public void setBlinkRate(int rate) 756: { 757: if (blinkTimer != null) 758: blinkTimer.setDelay(rate); 759: blinkRate = rate; 760: } 761: 762: /** 763: * Returns the current position of this <code>Caret</code> within the 764: * <code>Document</code>. 765: * 766: * @return the current position of this <code>Caret</code> within the 767: * <code>Document</code> 768: */ 769: public int getDot() 770: { 771: return dot; 772: } 773: 774: /** 775: * Moves the <code>dot</code> location without touching the 776: * <code>mark</code>. This is used when making a selection. 777: * 778: * @param dot the location where to move the dot 779: * 780: * @see #setDot(int) 781: */ 782: public void moveDot(int dot) 783: { 784: if (dot >= 0) 785: { 786: this.dot = dot; 787: handleHighlight(); 788: adjustVisibility(this); 789: appear(); 790: } 791: } 792: 793: /** 794: * Sets the current position of this <code>Caret</code> within the 795: * <code>Document</code>. This also sets the <code>mark</code> to the new 796: * location. 797: * 798: * @param dot 799: * the new position to be set 800: * @see #moveDot(int) 801: */ 802: public void setDot(int dot) 803: { 804: if (dot >= 0) 805: { 806: this.mark = dot; 807: this.dot = dot; 808: handleHighlight(); 809: adjustVisibility(this); 810: appear(); 811: } 812: } 813: 814: /** 815: * Show the caret (may be hidden due blinking) and adjust the timer not to 816: * hide it (possibly immediately). 817: * 818: * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) 819: */ 820: void appear() 821: { 822: // All machinery is only required if the carret is blinking. 823: if (blinkListener != null) 824: { 825: blinkListener.ignoreNextEvent = true; 826: 827: // If the caret is visible, erase the current position by repainting 828: // over. 829: if (visible) 830: repaint(); 831: 832: // Draw the caret in the new position. 833: visible = true; 834: 835: Rectangle area = null; 836: try 837: { 838: area = getComponent().modelToView(getDot()); 839: } 840: catch (BadLocationException ex) 841: { 842: assert false : "Unexpected bad caret location: " + getDot(); 843: } 844: if (area != null) 845: damage(area); 846: } 847: repaint(); 848: } 849: 850: /** 851: * Returns <code>true</code> if this <code>Caret</code> is currently visible, 852: * and <code>false</code> if it is not. 853: * 854: * @return <code>true</code> if this <code>Caret</code> is currently visible, 855: * and <code>false</code> if it is not 856: */ 857: public boolean isVisible() 858: { 859: return visible; 860: } 861: 862: /** 863: * Sets the visibility state of the caret. <code>true</code> shows the 864: * <code>Caret</code>, <code>false</code> hides it. 865: * 866: * @param v the visibility to set 867: */ 868: public void setVisible(boolean v) 869: { 870: if (v != visible) 871: { 872: visible = v; 873: if (visible) 874: if (textComponent.isEnabled() && textComponent.isEditable()) 875: { 876: if (blinkTimer == null) 877: initBlinkTimer(); 878: blinkTimer.start(); 879: } 880: else 881: { 882: if (blinkTimer != null) 883: blinkTimer.stop(); 884: } 885: Rectangle area = null; 886: try 887: { 888: area = getComponent().modelToView(getDot()); 889: } 890: catch (BadLocationException ex) 891: { 892: assert false: "Unexpected bad caret location: " + getDot(); 893: } 894: if (area != null) 895: damage(area); 896: } 897: } 898: 899: /** 900: * Returns the {@link Highlighter.HighlightPainter} that should be used 901: * to paint the selection. 902: * 903: * @return the {@link Highlighter.HighlightPainter} that should be used 904: * to paint the selection 905: */ 906: protected Highlighter.HighlightPainter getSelectionPainter() 907: { 908: return DefaultHighlighter.DefaultPainter; 909: } 910: 911: /** 912: * Updates the carets rectangle properties to the specified rectangle and 913: * repaints the caret. 914: * 915: * @param r the rectangle to set as the caret rectangle 916: */ 917: protected void damage(Rectangle r) 918: { 919: if (r == null) 920: return; 921: x = r.x; 922: y = r.y; 923: width = 1; 924: // height is normally set in paint and we leave it untouched. However, we 925: // must set a valid value here, since otherwise the painting mechanism 926: // sets a zero clip and never calls paint. 927: if (height <= 0) 928: height = getComponent().getHeight(); 929: repaint(); 930: } 931: 932: /** 933: * Adjusts the text component so that the caret is visible. This default 934: * implementation simply calls 935: * {@link JComponent#scrollRectToVisible(Rectangle)} on the text component. 936: * Subclasses may wish to change this. 937: */ 938: protected void adjustVisibility(Rectangle rect) 939: { 940: getComponent().scrollRectToVisible(rect); 941: } 942: 943: /** 944: * Initializes the blink timer. 945: */ 946: private void initBlinkTimer() 947: { 948: // Setup the blink timer. 949: blinkListener = new BlinkTimerListener(); 950: blinkTimer = new Timer(getBlinkRate(), blinkListener); 951: blinkTimer.setRepeats(true); 952: } 953: }