GNU Classpath (0.20) | |
Frames | No Frames |
1: /* DefaultCaret.java -- 2: Copyright (C) 2002, 2004, 2005, 2006 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: updateTimerStatus(); 435: } 436: 437: /** 438: * Sets the caret to <code>invisible</code>. 439: * 440: * @param event the <code>FocusEvent</code> 441: */ 442: public void focusLost(FocusEvent event) 443: { 444: if (event.isTemporary() == false) 445: { 446: setVisible(false); 447: // Stop the blinker, if running. 448: if (blinkTimer != null && blinkTimer.isRunning()) 449: blinkTimer.stop(); 450: } 451: } 452: 453: /** 454: * Install (if not present) and start the timer, if the caret must blink. The 455: * caret does not blink if it is invisible, or the component is disabled or 456: * not editable. 457: */ 458: private void updateTimerStatus() 459: { 460: if (textComponent.isEnabled() && textComponent.isEditable()) 461: { 462: if (blinkTimer == null) 463: initBlinkTimer(); 464: if (!blinkTimer.isRunning()) 465: blinkTimer.start(); 466: } 467: else 468: { 469: if (blinkTimer != null) 470: blinkTimer.stop(); 471: } 472: } 473: 474: /** 475: * Moves the caret to the position specified in the <code>MouseEvent</code>. 476: * This will cause a selection if the dot and mark are different. 477: * 478: * @param event the <code>MouseEvent</code> from which to fetch the position 479: */ 480: protected void moveCaret(MouseEvent event) 481: { 482: int newDot = getComponent().viewToModel(event.getPoint()); 483: moveDot(newDot); 484: } 485: 486: /** 487: * Repositions the caret to the position specified in the 488: * <code>MouseEvent</code>. 489: * 490: * @param event the <code>MouseEvent</code> from which to fetch the position 491: */ 492: protected void positionCaret(MouseEvent event) 493: { 494: int newDot = getComponent().viewToModel(event.getPoint()); 495: setDot(newDot); 496: } 497: 498: /** 499: * Deinstalls this <code>Caret</code> from the specified 500: * <code>JTextComponent</code>. This removes any listeners that have been 501: * registered by this <code>Caret</code>. 502: * 503: * @param c the text component from which to install this caret 504: */ 505: public void deinstall(JTextComponent c) 506: { 507: textComponent.removeFocusListener(this); 508: textComponent.removeMouseListener(this); 509: textComponent.removeMouseMotionListener(this); 510: textComponent.getDocument().removeDocumentListener(documentListener); 511: documentListener = null; 512: textComponent.removePropertyChangeListener(propertyChangeListener); 513: propertyChangeListener = null; 514: textComponent = null; 515: 516: // Deinstall blink timer if present. 517: if (blinkTimer != null) 518: blinkTimer.stop(); 519: blinkTimer = null; 520: } 521: 522: /** 523: * Installs this <code>Caret</code> on the specified 524: * <code>JTextComponent</code>. This registers a couple of listeners 525: * on the text component. 526: * 527: * @param c the text component on which to install this caret 528: */ 529: public void install(JTextComponent c) 530: { 531: textComponent = c; 532: textComponent.addFocusListener(this); 533: textComponent.addMouseListener(this); 534: textComponent.addMouseMotionListener(this); 535: propertyChangeListener = new PropertyChangeHandler(); 536: textComponent.addPropertyChangeListener(propertyChangeListener); 537: documentListener = new DocumentHandler(); 538: textComponent.getDocument().addDocumentListener(documentListener); 539: 540: repaint(); 541: } 542: 543: /** 544: * Sets the current visual position of this <code>Caret</code>. 545: * 546: * @param p the Point to use for the saved location. May be <code>null</code> 547: * to indicate that there is no visual location 548: */ 549: public void setMagicCaretPosition(Point p) 550: { 551: magicCaretPosition = p; 552: } 553: 554: /** 555: * Returns the current visual position of this <code>Caret</code>. 556: * 557: * @return the current visual position of this <code>Caret</code> 558: * 559: * @see #setMagicCaretPosition 560: */ 561: public Point getMagicCaretPosition() 562: { 563: return magicCaretPosition; 564: } 565: 566: /** 567: * Returns the current position of the <code>mark</code>. The 568: * <code>mark</code> marks the location in the <code>Document</code> that 569: * is the end of a selection. If there is no selection, the <code>mark</code> 570: * is the same as the <code>dot</code>. 571: * 572: * @return the current position of the mark 573: */ 574: public int getMark() 575: { 576: return mark; 577: } 578: 579: private void handleHighlight() 580: { 581: Highlighter highlighter = textComponent.getHighlighter(); 582: 583: if (highlighter == null) 584: return; 585: 586: int p0 = Math.min(dot, mark); 587: int p1 = Math.max(dot, mark); 588: 589: if (selectionVisible && p0 != p1) 590: { 591: try 592: { 593: if (highlightEntry == null) 594: highlightEntry = highlighter.addHighlight(p0, p1, getSelectionPainter()); 595: else 596: highlighter.changeHighlight(highlightEntry, p0, p1); 597: } 598: catch (BadLocationException e) 599: { 600: // This should never happen. 601: throw new InternalError(); 602: } 603: } 604: else 605: { 606: if (highlightEntry != null) 607: { 608: highlighter.removeHighlight(highlightEntry); 609: highlightEntry = null; 610: } 611: } 612: } 613: 614: /** 615: * Sets the visiblity state of the selection. 616: * 617: * @param v <code>true</code> if the selection should be visible, 618: * <code>false</code> otherwise 619: */ 620: public void setSelectionVisible(boolean v) 621: { 622: if (selectionVisible == v) 623: return; 624: 625: selectionVisible = v; 626: handleHighlight(); 627: repaint(); 628: } 629: 630: /** 631: * Returns <code>true</code> if the selection is currently visible, 632: * <code>false</code> otherwise. 633: * 634: * @return <code>true</code> if the selection is currently visible, 635: * <code>false</code> otherwise 636: */ 637: public boolean isSelectionVisible() 638: { 639: return selectionVisible; 640: } 641: 642: /** 643: * Causes the <code>Caret</code> to repaint itself. 644: */ 645: protected final void repaint() 646: { 647: getComponent().repaint(x, y, width, height); 648: } 649: 650: /** 651: * Paints this <code>Caret</code> using the specified <code>Graphics</code> 652: * context. 653: * 654: * @param g the graphics context to use 655: */ 656: public void paint(Graphics g) 657: { 658: JTextComponent comp = getComponent(); 659: if (comp == null) 660: return; 661: 662: int dot = getDot(); 663: Rectangle rect = null; 664: 665: try 666: { 667: rect = textComponent.modelToView(dot); 668: } 669: catch (BadLocationException e) 670: { 671: AssertionError ae; 672: ae = new AssertionError("Unexpected bad caret location: " + dot); 673: ae.initCause(e); 674: throw ae; 675: } 676: 677: if (rect == null) 678: return; 679: 680: // Check if paint has possibly been called directly, without a previous 681: // call to damage(). In this case we need to do some cleanup first. 682: if ((x != rect.x) || (y != rect.y)) 683: { 684: repaint(); // Erase previous location of caret. 685: x = rect.x; 686: y = rect.y; 687: width = 1; 688: height = rect.height; 689: } 690: 691: // Now draw the caret on the new position if visible. 692: if (visible) 693: { 694: g.setColor(textComponent.getCaretColor()); 695: g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height); 696: } 697: } 698: 699: /** 700: * Returns all registered event listeners of the specified type. 701: * 702: * @param listenerType the type of listener to return 703: * 704: * @return all registered event listeners of the specified type 705: */ 706: public EventListener[] getListeners(Class listenerType) 707: { 708: return listenerList.getListeners(listenerType); 709: } 710: 711: /** 712: * Registers a {@link ChangeListener} that is notified whenever that state 713: * of this <code>Caret</code> changes. 714: * 715: * @param listener the listener to register to this caret 716: */ 717: public void addChangeListener(ChangeListener listener) 718: { 719: listenerList.add(ChangeListener.class, listener); 720: } 721: 722: /** 723: * Removes a {@link ChangeListener} from the list of registered listeners. 724: * 725: * @param listener the listener to remove 726: */ 727: public void removeChangeListener(ChangeListener listener) 728: { 729: listenerList.remove(ChangeListener.class, listener); 730: } 731: 732: /** 733: * Returns all registered {@link ChangeListener}s of this <code>Caret</code>. 734: * 735: * @return all registered {@link ChangeListener}s of this <code>Caret</code> 736: */ 737: public ChangeListener[] getChangeListeners() 738: { 739: return (ChangeListener[]) getListeners(ChangeListener.class); 740: } 741: 742: /** 743: * Notifies all registered {@link ChangeListener}s that the state 744: * of this <code>Caret</code> has changed. 745: */ 746: protected void fireStateChanged() 747: { 748: ChangeListener[] listeners = getChangeListeners(); 749: 750: for (int index = 0; index < listeners.length; ++index) 751: listeners[index].stateChanged(changeEvent); 752: } 753: 754: /** 755: * Returns the <code>JTextComponent</code> on which this <code>Caret</code> 756: * is installed. 757: * 758: * @return the <code>JTextComponent</code> on which this <code>Caret</code> 759: * is installed 760: */ 761: protected final JTextComponent getComponent() 762: { 763: return textComponent; 764: } 765: 766: /** 767: * Returns the blink rate of this <code>Caret</code> in milliseconds. 768: * A value of <code>0</code> means that the caret does not blink. 769: * 770: * @return the blink rate of this <code>Caret</code> or <code>0</code> if 771: * this caret does not blink 772: */ 773: public int getBlinkRate() 774: { 775: return blinkRate; 776: } 777: 778: /** 779: * Sets the blink rate of this <code>Caret</code> in milliseconds. 780: * A value of <code>0</code> means that the caret does not blink. 781: * 782: * @param rate the new blink rate to set 783: */ 784: public void setBlinkRate(int rate) 785: { 786: if (blinkTimer != null) 787: blinkTimer.setDelay(rate); 788: blinkRate = rate; 789: } 790: 791: /** 792: * Returns the current position of this <code>Caret</code> within the 793: * <code>Document</code>. 794: * 795: * @return the current position of this <code>Caret</code> within the 796: * <code>Document</code> 797: */ 798: public int getDot() 799: { 800: return dot; 801: } 802: 803: /** 804: * Moves the <code>dot</code> location without touching the 805: * <code>mark</code>. This is used when making a selection. 806: * 807: * @param dot the location where to move the dot 808: * 809: * @see #setDot(int) 810: */ 811: public void moveDot(int dot) 812: { 813: if (dot >= 0) 814: { 815: this.dot = dot; 816: handleHighlight(); 817: adjustVisibility(this); 818: appear(); 819: } 820: } 821: 822: /** 823: * Sets the current position of this <code>Caret</code> within the 824: * <code>Document</code>. This also sets the <code>mark</code> to the new 825: * location. 826: * 827: * @param dot 828: * the new position to be set 829: * @see #moveDot(int) 830: */ 831: public void setDot(int dot) 832: { 833: if (dot >= 0) 834: { 835: Document doc = textComponent.getDocument(); 836: if (doc != null) 837: this.dot = Math.min(dot, doc.getLength()); 838: this.dot = Math.max(this.dot, 0); 839: this.mark = dot; 840: handleHighlight(); 841: adjustVisibility(this); 842: appear(); 843: } 844: } 845: 846: /** 847: * Show the caret (may be hidden due blinking) and adjust the timer not to 848: * hide it (possibly immediately). 849: * 850: * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) 851: */ 852: void appear() 853: { 854: // All machinery is only required if the carret is blinking. 855: if (blinkListener != null) 856: { 857: blinkListener.ignoreNextEvent = true; 858: 859: // If the caret is visible, erase the current position by repainting 860: // over. 861: if (visible) 862: repaint(); 863: 864: // Draw the caret in the new position. 865: visible = true; 866: 867: Rectangle area = null; 868: int dot = getDot(); 869: try 870: { 871: area = getComponent().modelToView(dot); 872: } 873: catch (BadLocationException e) 874: { 875: AssertionError ae; 876: ae = new AssertionError("Unexpected bad caret location: " + dot); 877: ae.initCause(e); 878: throw ae; 879: } 880: if (area != null) 881: damage(area); 882: } 883: repaint(); 884: } 885: 886: /** 887: * Returns <code>true</code> if this <code>Caret</code> is currently visible, 888: * and <code>false</code> if it is not. 889: * 890: * @return <code>true</code> if this <code>Caret</code> is currently visible, 891: * and <code>false</code> if it is not 892: */ 893: public boolean isVisible() 894: { 895: return visible; 896: } 897: 898: /** 899: * Sets the visibility state of the caret. <code>true</code> shows the 900: * <code>Caret</code>, <code>false</code> hides it. 901: * 902: * @param v the visibility to set 903: */ 904: public void setVisible(boolean v) 905: { 906: if (v != visible) 907: { 908: visible = v; 909: updateTimerStatus(); 910: Rectangle area = null; 911: int dot = getDot(); 912: try 913: { 914: area = getComponent().modelToView(dot); 915: } 916: catch (BadLocationException e) 917: { 918: AssertionError ae; 919: ae = new AssertionError("Unexpected bad caret location: " + dot); 920: ae.initCause(e); 921: throw ae; 922: } 923: if (area != null) 924: damage(area); 925: } 926: } 927: 928: /** 929: * Returns the {@link Highlighter.HighlightPainter} that should be used 930: * to paint the selection. 931: * 932: * @return the {@link Highlighter.HighlightPainter} that should be used 933: * to paint the selection 934: */ 935: protected Highlighter.HighlightPainter getSelectionPainter() 936: { 937: return DefaultHighlighter.DefaultPainter; 938: } 939: 940: /** 941: * Updates the carets rectangle properties to the specified rectangle and 942: * repaints the caret. 943: * 944: * @param r the rectangle to set as the caret rectangle 945: */ 946: protected void damage(Rectangle r) 947: { 948: if (r == null) 949: return; 950: x = r.x; 951: y = r.y; 952: width = 1; 953: // height is normally set in paint and we leave it untouched. However, we 954: // must set a valid value here, since otherwise the painting mechanism 955: // sets a zero clip and never calls paint. 956: if (height <= 0) 957: height = getComponent().getHeight(); 958: repaint(); 959: } 960: 961: /** 962: * Adjusts the text component so that the caret is visible. This default 963: * implementation simply calls 964: * {@link JComponent#scrollRectToVisible(Rectangle)} on the text component. 965: * Subclasses may wish to change this. 966: */ 967: protected void adjustVisibility(Rectangle rect) 968: { 969: getComponent().scrollRectToVisible(rect); 970: } 971: 972: /** 973: * Initializes the blink timer. 974: */ 975: private void initBlinkTimer() 976: { 977: // Setup the blink timer. 978: blinkListener = new BlinkTimerListener(); 979: blinkTimer = new Timer(getBlinkRate(), blinkListener); 980: blinkTimer.setRepeats(true); 981: } 982: }
GNU Classpath (0.20) |