GNU Classpath (0.18) | ||
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.FocusEvent; 44: import java.awt.event.FocusListener; 45: import java.awt.event.MouseEvent; 46: import java.awt.event.MouseListener; 47: import java.awt.event.MouseMotionListener; 48: import java.util.EventListener; 49: 50: import javax.swing.event.ChangeEvent; 51: import javax.swing.event.ChangeListener; 52: import javax.swing.event.EventListenerList; 53: 54: /** 55: * The default implementation of the {@link Caret} interface. 56: * 57: * @author orgininal author unknown 58: * @author Roman Kennke (roman@kennke.org) 59: */ 60: public class DefaultCaret extends Rectangle 61: implements Caret, FocusListener, MouseListener, MouseMotionListener 62: { 63: /** 64: * The serial version UID for DefaultCaret. 65: */ 66: private static final long serialVersionUID = 228155774675466193L; 67: 68: /** 69: * The <code>ChangeEvent</code> that is fired by {@link #fireStateChanged()}. 70: */ 71: protected ChangeEvent changeEvent = new ChangeEvent(this); 72: 73: /** 74: * Stores all registered event listeners. 75: */ 76: protected EventListenerList listenerList = new EventListenerList(); 77: 78: /** 79: * The text component in which this caret is installed. 80: */ 81: private JTextComponent textComponent; 82: 83: /** 84: * Indicates if the selection should be visible or not. 85: */ 86: private boolean selectionVisible = true; 87: 88: /** 89: * The blink rate of this <code>Caret</code>. 90: */ 91: private int blinkRate = 500; 92: 93: /** 94: * The current dot position. 95: */ 96: private int dot = 0; 97: 98: /** 99: * The current mark position. 100: */ 101: private int mark = 0; 102: 103: /** 104: * The current visual caret position. 105: */ 106: private Point magicCaretPosition = null; 107: 108: /** 109: * Indicates if this <code>Caret</code> is currently visible or not. 110: */ 111: private boolean visible = true; 112: 113: /** 114: * The current highlight entry. 115: */ 116: private Object highlightEntry; 117: 118: /** 119: * Moves the caret position when the mouse is dragged over the text 120: * component, modifying the selection accordingly. 121: * 122: * @param event the <code>MouseEvent</code> describing the drag operation 123: */ 124: public void mouseDragged(MouseEvent event) 125: { 126: // FIXME: Implement this properly. 127: } 128: 129: /** 130: * Indicates a mouse movement over the text component. Does nothing here. 131: * 132: * @param event the <code>MouseEvent</code> describing the mouse operation 133: */ 134: public void mouseMoved(MouseEvent event) 135: { 136: // Nothing to do here. 137: } 138: 139: /** 140: * When the click is received from Button 1 then the following actions 141: * are performed here: 142: * 143: * <ul> 144: * <li>If we receive a double click, the caret position (dot) is set 145: * to the position associated to the mouse click and the word at 146: * this location is selected.</li> 147: * <li>If we receive a triple click, the caret position (dot) is set 148: * to the position associated to the mouse click and the line at 149: * this location is selected.</li> 150: * </ul> 151: * 152: * @param event the <code>MouseEvent</code> describing the click operation 153: */ 154: public void mouseClicked(MouseEvent event) 155: { 156: // FIXME: Implement this properly. 157: } 158: 159: /** 160: * Indicates that the mouse has entered the text component. Nothing is done 161: * here. 162: * 163: * @param event the <code>MouseEvent</code> describing the mouse operation 164: */ 165: public void mouseEntered(MouseEvent event) 166: { 167: // Nothing to do here. 168: } 169: 170: /** 171: * Indicates that the mouse has exited the text component. Nothing is done 172: * here. 173: * 174: * @param event the <code>MouseEvent</code> describing the mouse operation 175: */ 176: public void mouseExited(MouseEvent event) 177: { 178: } 179: 180: /** 181: * If the button 1 is pressed, the caret position is updated to the 182: * position of the mouse click and the text component requests the input 183: * focus if it is enabled. If the SHIFT key is held down, the caret will 184: * be moved, which might select the text between the old and new location. 185: * 186: * @param event the <code>MouseEvent</code> describing the press operation 187: */ 188: public void mousePressed(MouseEvent event) 189: { 190: // FIXME: Implement this properly. 191: } 192: 193: /** 194: * Indicates that a mouse button has been released on the text component. 195: * Nothing is done here. 196: * 197: * @param event the <code>MouseEvent</code> describing the mouse operation 198: */ 199: public void mouseReleased(MouseEvent event) 200: { 201: // Nothing to do here. 202: } 203: 204: /** 205: * Sets the caret to <code>visible</code> if the text component is editable. 206: * 207: * @param event the <code>FocusEvent</code> 208: */ 209: public void focusGained(FocusEvent event) 210: { 211: } 212: 213: /** 214: * Sets the caret to <code>invisible</code>. 215: * 216: * @param event the <code>FocusEvent</code> 217: */ 218: public void focusLost(FocusEvent event) 219: { 220: } 221: 222: /** 223: * Moves the caret to the position specified in the <code>MouseEvent</code>. 224: * This will cause a selection if the dot and mark are different. 225: * 226: * @param event the <code>MouseEvent</code> from which to fetch the position 227: */ 228: protected void moveCaret(MouseEvent event) 229: { 230: // FIXME: Implement this properly. 231: } 232: 233: /** 234: * Repositions the caret to the position specified in the 235: * <code>MouseEvent</code>. 236: * 237: * @param event the <code>MouseEvent</code> from which to fetch the position 238: */ 239: protected void positionCaret(MouseEvent event) 240: { 241: // FIXME: Implement this properly. 242: } 243: 244: /** 245: * Deinstalls this <code>Caret</code> from the specified 246: * <code>JTextComponent</code>. This removes any listeners that have been 247: * registered by this <code>Caret</code>. 248: * 249: * @param c the text component from which to install this caret 250: */ 251: public void deinstall(JTextComponent c) 252: { 253: textComponent.removeFocusListener(this); 254: textComponent.removeMouseListener(this); 255: textComponent.removeMouseMotionListener(this); 256: textComponent = null; 257: } 258: 259: /** 260: * Installs this <code>Caret</code> on the specified 261: * <code>JTextComponent</code>. This registers a couple of listeners 262: * on the text component. 263: * 264: * @param c the text component on which to install this caret 265: */ 266: public void install(JTextComponent c) 267: { 268: textComponent = c; 269: textComponent.addFocusListener(this); 270: textComponent.addMouseListener(this); 271: textComponent.addMouseMotionListener(this); 272: repaint(); 273: } 274: 275: /** 276: * Sets the current visual position of this <code>Caret</code>. 277: * 278: * @param p the Point to use for the saved location. May be <code>null</code> 279: * to indicate that there is no visual location 280: */ 281: public void setMagicCaretPosition(Point p) 282: { 283: magicCaretPosition = p; 284: } 285: 286: /** 287: * Returns the current visual position of this <code>Caret</code>. 288: * 289: * @return the current visual position of this <code>Caret</code> 290: * 291: * @see #setMagicCaretPosition 292: */ 293: public Point getMagicCaretPosition() 294: { 295: return magicCaretPosition; 296: } 297: 298: /** 299: * Returns the current position of the <code>mark</code>. The 300: * <code>mark</code> marks the location in the <code>Document</code> that 301: * is the end of a selection. If there is no selection, the <code>mark</code> 302: * is the same as the <code>dot</code>. 303: * 304: * @return the current position of the mark 305: */ 306: public int getMark() 307: { 308: return mark; 309: } 310: 311: private void handleHighlight() 312: { 313: Highlighter highlighter = textComponent.getHighlighter(); 314: 315: if (highlighter == null) 316: return; 317: 318: int p0 = Math.min(dot, mark); 319: int p1 = Math.max(dot, mark); 320: 321: if (selectionVisible && p0 != p1) 322: { 323: try 324: { 325: if (highlightEntry == null) 326: highlightEntry = highlighter.addHighlight(p0, p1, getSelectionPainter()); 327: else 328: highlighter.changeHighlight(highlightEntry, p0, p1); 329: } 330: catch (BadLocationException e) 331: { 332: // This should never happen. 333: throw new InternalError(); 334: } 335: } 336: else 337: { 338: if (highlightEntry != null) 339: { 340: highlighter.removeHighlight(highlightEntry); 341: highlightEntry = null; 342: } 343: } 344: } 345: 346: /** 347: * Sets the visiblity state of the selection. 348: * 349: * @param v <code>true</code> if the selection should be visible, 350: * <code>false</code> otherwise 351: */ 352: public void setSelectionVisible(boolean v) 353: { 354: if (selectionVisible == v) 355: return; 356: 357: selectionVisible = v; 358: handleHighlight(); 359: repaint(); 360: } 361: 362: /** 363: * Returns <code>true</code> if the selection is currently visible, 364: * <code>false</code> otherwise. 365: * 366: * @return <code>true</code> if the selection is currently visible, 367: * <code>false</code> otherwise 368: */ 369: public boolean isSelectionVisible() 370: { 371: return selectionVisible; 372: } 373: 374: /** 375: * Causes the <code>Caret</code> to repaint itself. 376: */ 377: protected final void repaint() 378: { 379: // FIXME: Is this good? This possibly causes alot of the component 380: // hierarchy to be repainted on every caret blink. 381: if (textComponent != null) 382: textComponent.repaint(); 383: } 384: 385: /** 386: * Paints this <code>Caret</code> using the specified <code>Graphics</code> 387: * context. 388: * 389: * @param g the graphics context to use 390: */ 391: public void paint(Graphics g) 392: { 393: if (textComponent == null) 394: return; 395: 396: int dot = getDot(); 397: Rectangle rect = null; 398: 399: try 400: { 401: rect = textComponent.modelToView(dot); 402: } 403: catch (BadLocationException e) 404: { 405: // This should never happen as dot should be always valid. 406: return; 407: } 408: 409: if (rect == null) 410: return; 411: 412: // First we need to delete the old caret. 413: // FIXME: Implement deleting of old caret. 414: 415: // Now draw the caret on the new position if visible. 416: if (visible) 417: { 418: g.setColor(textComponent.getCaretColor()); 419: g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height); 420: } 421: } 422: 423: /** 424: * Returns all registered event listeners of the specified type. 425: * 426: * @param listenerType the type of listener to return 427: * 428: * @return all registered event listeners of the specified type 429: */ 430: public EventListener[] getListeners(Class listenerType) 431: { 432: return listenerList.getListeners(listenerType); 433: } 434: 435: /** 436: * Registers a {@link ChangeListener} that is notified whenever that state 437: * of this <code>Caret</code> changes. 438: * 439: * @param listener the listener to register to this caret 440: */ 441: public void addChangeListener(ChangeListener listener) 442: { 443: listenerList.add(ChangeListener.class, listener); 444: } 445: 446: /** 447: * Removes a {@link ChangeListener} from the list of registered listeners. 448: * 449: * @param listener the listener to remove 450: */ 451: public void removeChangeListener(ChangeListener listener) 452: { 453: listenerList.remove(ChangeListener.class, listener); 454: } 455: 456: /** 457: * Returns all registered {@link ChangeListener}s of this <code>Caret</code>. 458: * 459: * @return all registered {@link ChangeListener}s of this <code>Caret</code> 460: */ 461: public ChangeListener[] getChangeListeners() 462: { 463: return (ChangeListener[]) getListeners(ChangeListener.class); 464: } 465: 466: /** 467: * Notifies all registered {@link ChangeListener}s that the state 468: * of this <code>Caret</code> has changed. 469: */ 470: protected void fireStateChanged() 471: { 472: ChangeListener[] listeners = getChangeListeners(); 473: 474: for (int index = 0; index < listeners.length; ++index) 475: listeners[index].stateChanged(changeEvent); 476: } 477: 478: /** 479: * Returns the <code>JTextComponent</code> on which this <code>Caret</code> 480: * is installed. 481: * 482: * @return the <code>JTextComponent</code> on which this <code>Caret</code> 483: * is installed 484: */ 485: protected final JTextComponent getComponent() 486: { 487: return textComponent; 488: } 489: 490: /** 491: * Returns the blink rate of this <code>Caret</code> in milliseconds. 492: * A value of <code>0</code> means that the caret does not blink. 493: * 494: * @return the blink rate of this <code>Caret</code> or <code>0</code> if 495: * this caret does not blink 496: */ 497: public int getBlinkRate() 498: { 499: return blinkRate; 500: } 501: 502: /** 503: * Sets the blink rate of this <code>Caret</code> in milliseconds. 504: * A value of <code>0</code> means that the caret does not blink. 505: * 506: * @param rate the new blink rate to set 507: */ 508: public void setBlinkRate(int rate) 509: { 510: blinkRate = rate; 511: } 512: 513: /** 514: * Returns the current position of this <code>Caret</code> within the 515: * <code>Document</code>. 516: * 517: * @return the current position of this <code>Caret</code> within the 518: * <code>Document</code> 519: */ 520: public int getDot() 521: { 522: return dot; 523: } 524: 525: /** 526: * Moves the <code>dot</code> location without touching the 527: * <code>mark</code>. This is used when making a selection. 528: * 529: * @param dot the location where to move the dot 530: * 531: * @see #setDot(int) 532: */ 533: public void moveDot(int dot) 534: { 535: this.dot = dot; 536: handleHighlight(); 537: repaint(); 538: } 539: 540: /** 541: * Sets the current position of this <code>Caret</code> within the 542: * <code>Document</code>. This also sets the <code>mark</code> to the 543: * new location. 544: * 545: * @param dot the new position to be set 546: * 547: * @see #moveDot(int) 548: */ 549: public void setDot(int dot) 550: { 551: this.dot = dot; 552: this.mark = dot; 553: handleHighlight(); 554: repaint(); 555: } 556: 557: /** 558: * Returns <code>true</code> if this <code>Caret</code> is currently visible, 559: * and <code>false</code> if it is not. 560: * 561: * @return <code>true</code> if this <code>Caret</code> is currently visible, 562: * and <code>false</code> if it is not 563: */ 564: public boolean isVisible() 565: { 566: return visible; 567: } 568: 569: /** 570: * Sets the visibility state of the caret. <code>true</code> shows the 571: * <code>Caret</code>, <code>false</code> hides it. 572: * 573: * @param v the visibility to set 574: */ 575: public void setVisible(boolean v) 576: { 577: visible = v; 578: repaint(); 579: } 580: 581: /** 582: * Returns the {@link Highlighter.HighlightPainter} that should be used 583: * to paint the selection. 584: * 585: * @return the {@link Highlighter.HighlightPainter} that should be used 586: * to paint the selection 587: */ 588: protected Highlighter.HighlightPainter getSelectionPainter() 589: { 590: return DefaultHighlighter.DefaultPainter; 591: } 592: }
GNU Classpath (0.18) |