Source for javax.swing.text.DefaultCaret

   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.beans.PropertyChangeEvent;
  49: import java.beans.PropertyChangeListener;
  50: import java.util.EventListener;
  51: 
  52: import javax.swing.SwingUtilities;
  53: import javax.swing.event.ChangeEvent;
  54: import javax.swing.event.ChangeListener;
  55: import javax.swing.event.DocumentEvent;
  56: import javax.swing.event.DocumentListener;
  57: import javax.swing.event.EventListenerList;
  58: 
  59: /**
  60:  * The default implementation of the {@link Caret} interface.
  61:  *
  62:  * @author orgininal author unknown
  63:  * @author Roman Kennke (roman@kennke.org)
  64:  */
  65: public class DefaultCaret extends Rectangle
  66:   implements Caret, FocusListener, MouseListener, MouseMotionListener
  67: {
  68:   /**
  69:    * Listens for changes in the text component's document and updates the
  70:    * caret accordingly.
  71:    * 
  72:    * @author Roman Kennke (kennke@aicas.com)
  73:    */
  74:   private class DocumentHandler implements DocumentListener
  75:   {
  76:     /**
  77:      * Receives notification that some text attributes have changed. No action
  78:      * is taken here.
  79:      *
  80:      * @param event the document event
  81:      */
  82:     public void changedUpdate(DocumentEvent event)
  83:     {
  84:       // Nothing to do here.
  85:     }
  86: 
  87:     /**
  88:      * Receives notification that some text has been inserted from the text
  89:      * component. The caret is moved forward accordingly.
  90:      *
  91:      * @param event the document event
  92:      */
  93:     public void insertUpdate(DocumentEvent event)
  94:     {
  95:       if (policy == ALWAYS_UPDATE || 
  96:           (SwingUtilities.isEventDispatchThread() && 
  97:            policy == UPDATE_WHEN_ON_EDT))
  98:         {        
  99:           int dot = getDot();
 100:           setDot(dot + event.getLength());
 101:         }
 102:     }
 103: 
 104:     /**
 105:      * Receives notification that some text has been removed into the text
 106:      * component. The caret is moved backwards accordingly.
 107:      *
 108:      * @param event the document event
 109:      */
 110:     public void removeUpdate(DocumentEvent event)
 111:     {
 112:       if (policy == ALWAYS_UPDATE || 
 113:           (SwingUtilities.isEventDispatchThread() && 
 114:            policy == UPDATE_WHEN_ON_EDT))
 115:         {
 116:           int dot = getDot();
 117:           setDot(dot - event.getLength());
 118:         }
 119:       else if (policy == NEVER_UPDATE)
 120:         {
 121:           int docLength = event.getDocument().getLength();
 122:           if (getDot() > docLength)
 123:             setDot(docLength);
 124:         }
 125:     }
 126:   }
 127: 
 128:   /**
 129:    * Listens for property changes on the text document. This is used to add and
 130:    * remove our document listener, if the document of the text component has
 131:    * changed.
 132:    *
 133:    * @author Roman Kennke (kennke@aicas.com)
 134:    */
 135:   private class PropertyChangeHandler implements PropertyChangeListener
 136:   {
 137: 
 138:     /**
 139:      * Receives notification when a property has changed on the text component.
 140:      * This adds/removes our document listener from the text component's
 141:      * document when the document changes.
 142:      *
 143:      * @param e the property change event
 144:      */
 145:     public void propertyChange(PropertyChangeEvent e)
 146:     {
 147:       if (e.getPropertyName().equals("document"))
 148:         {
 149:           Document oldDoc = (Document) e.getOldValue();
 150:           oldDoc.removeDocumentListener(documentListener);
 151:           Document newDoc = (Document) e.getNewValue();
 152:           newDoc.addDocumentListener(documentListener);
 153:         }
 154:     }
 155:     
 156:   }
 157: 
 158:   /** The serialization UID (compatible with JDK1.5). */
 159:   private static final long serialVersionUID = 4325555698756477346L;
 160:   
 161:   /**
 162:    * Indicates the Caret position should always be updated after Document
 163:    * changes even if the updates are not performed on the Event Dispatching
 164:    * thread.
 165:    * 
 166:    * @since 1.5
 167:    */
 168:   public static final int ALWAYS_UPDATE = 2;
 169: 
 170:   /**
 171:    * Indicates the Caret position should not be changed unless the Document
 172:    * length becomes less than the Caret position, in which case the Caret
 173:    * is moved to the end of the Document.
 174:    * 
 175:    * @since 1.5
 176:    */
 177:   public static final int NEVER_UPDATE = 1;
 178:   
 179:   /** 
 180:    * Indicates the Caret position should be updated only if Document changes
 181:    * are made on the Event Dispatcher thread.
 182:    *  
 183:    * @since 1.5
 184:    */
 185:   public static final int UPDATE_WHEN_ON_EDT = 0;
 186:   
 187:   /** Keeps track of the current update policy **/
 188:   int policy = UPDATE_WHEN_ON_EDT;
 189:     
 190:   /**
 191:    * The <code>ChangeEvent</code> that is fired by {@link #fireStateChanged()}.
 192:    */
 193:   protected ChangeEvent changeEvent = new ChangeEvent(this);
 194: 
 195:   /**
 196:    * Stores all registered event listeners.
 197:    */
 198:   protected EventListenerList listenerList = new EventListenerList();
 199: 
 200:   /**
 201:    * Our document listener.
 202:    */
 203:   DocumentListener documentListener;
 204: 
 205:   /**
 206:    * Our property listener.
 207:    */
 208:   PropertyChangeListener propertyChangeListener;
 209: 
 210:   /**
 211:    * The text component in which this caret is installed.
 212:    */
 213:   private JTextComponent textComponent;
 214: 
 215:   /**
 216:    * Indicates if the selection should be visible or not.
 217:    */
 218:   private boolean selectionVisible = true;
 219: 
 220:   /**
 221:    * The blink rate of this <code>Caret</code>.
 222:    */
 223:   private int blinkRate = 500;
 224: 
 225:   /**
 226:    * The current dot position.
 227:    */
 228:   private int dot = 0;
 229: 
 230:   /**
 231:    * The current mark position.
 232:    */
 233:   private int mark = 0;
 234: 
 235:   /**
 236:    * The current visual caret position.
 237:    */
 238:   private Point magicCaretPosition = null;
 239: 
 240:   /**
 241:    * Indicates if this <code>Caret</code> is currently visible or not.
 242:    */
 243:   private boolean visible = true;
 244: 
 245:   /**
 246:    * The current highlight entry.
 247:    */
 248:   private Object highlightEntry;
 249: 
 250:   /**
 251:    * Sets the Caret update policy.
 252:    *    
 253:    * @param policy the new policy.  Valid values are:
 254:    * ALWAYS_UPDATE: always update the Caret position, even when Document
 255:    * updates don't occur on the Event Dispatcher thread.
 256:    * NEVER_UPDATE: don't update the Caret position unless the Document
 257:    * length becomes less than the Caret position (then update the
 258:    * Caret to the end of the Document).
 259:    * UPDATE_WHEN_ON_EDT: update the Caret position when the 
 260:    * Document updates occur on the Event Dispatcher thread.  This is the 
 261:    * default.
 262:    * 
 263:    * @since 1.5
 264:    * @throws IllegalArgumentException if policy is not one of the above.
 265:    */
 266:   public void setUpdatePolicy (int policy)
 267:   {
 268:     if (policy != ALWAYS_UPDATE && policy != NEVER_UPDATE
 269:         && policy != UPDATE_WHEN_ON_EDT)
 270:       throw new 
 271:         IllegalArgumentException
 272:         ("policy must be ALWAYS_UPDATE, NEVER__UPDATE, or UPDATE_WHEN_ON_EDT");
 273:     this.policy = policy;
 274:   }
 275:   
 276:   /**
 277:    * Gets the caret update policy.
 278:    * 
 279:    * @return the caret update policy.
 280:    * @since 1.5
 281:    */
 282:   public int getUpdatePolicy ()
 283:   {
 284:     return policy;
 285:   }
 286:   
 287:   /**
 288:    * Moves the caret position when the mouse is dragged over the text
 289:    * component, modifying the selection accordingly.
 290:    *
 291:    * @param event the <code>MouseEvent</code> describing the drag operation
 292:    */
 293:   public void mouseDragged(MouseEvent event)
 294:   {
 295:     // FIXME: Implement this properly.
 296:   }
 297: 
 298:   /**
 299:    * Indicates a mouse movement over the text component. Does nothing here.
 300:    *
 301:    * @param event the <code>MouseEvent</code> describing the mouse operation
 302:    */
 303:   public void mouseMoved(MouseEvent event)
 304:   {
 305:     // Nothing to do here.
 306:   }
 307: 
 308:   /**
 309:    * When the click is received from Button 1 then the following actions
 310:    * are performed here:
 311:    *
 312:    * <ul>
 313:    * <li>If we receive a double click, the caret position (dot) is set
 314:    *   to the position associated to the mouse click and the word at
 315:    *   this location is selected.</li>
 316:    * <li>If we receive a triple click, the caret position (dot) is set
 317:    *   to the position associated to the mouse click and the line at
 318:    *   this location is selected.</li>
 319:    * </ul>
 320:    *
 321:    * @param event the <code>MouseEvent</code> describing the click operation
 322:    */
 323:   public void mouseClicked(MouseEvent event)
 324:   {
 325:     // FIXME: Implement this properly.
 326:   }
 327: 
 328:   /**
 329:    * Indicates that the mouse has entered the text component. Nothing is done
 330:    * here.
 331:    *
 332:    * @param event the <code>MouseEvent</code> describing the mouse operation
 333:    */
 334:   public void mouseEntered(MouseEvent event)
 335:   {
 336:     // Nothing to do here.
 337:   }
 338: 
 339:   /**
 340:    * Indicates that the mouse has exited the text component. Nothing is done
 341:    * here.
 342:    *
 343:    * @param event the <code>MouseEvent</code> describing the mouse operation
 344:    */
 345:   public void mouseExited(MouseEvent event)
 346:   {
 347:     // TODO: What to do here, if anything?
 348:   }
 349: 
 350:   /**
 351:    * If the button 1 is pressed, the caret position is updated to the
 352:    * position of the mouse click and the text component requests the input
 353:    * focus if it is enabled. If the SHIFT key is held down, the caret will
 354:    * be moved, which might select the text between the old and new location.
 355:    *
 356:    * @param event the <code>MouseEvent</code> describing the press operation
 357:    */
 358:   public void mousePressed(MouseEvent event)
 359:   {
 360:     // FIXME: Implement this properly.
 361:     if (!(event.getButton() == MouseEvent.BUTTON1))
 362:       return;
 363:     setDot(textComponent.viewToModel(event.getPoint()));
 364:   }
 365: 
 366:   /**
 367:    * Indicates that a mouse button has been released on the text component.
 368:    * Nothing is done here.
 369:    *
 370:    * @param event the <code>MouseEvent</code> describing the mouse operation
 371:    */
 372:   public void mouseReleased(MouseEvent event)
 373:   {
 374:     // Nothing to do here.
 375:   }
 376: 
 377:   /**
 378:    * Sets the caret to <code>visible</code> if the text component is editable.
 379:    *
 380:    * @param event the <code>FocusEvent</code>
 381:    */
 382:   public void focusGained(FocusEvent event)
 383:   {
 384:     // TODO: Implement this properly.
 385:   }
 386: 
 387:   /**
 388:    * Sets the caret to <code>invisible</code>.
 389:    *
 390:    * @param event the <code>FocusEvent</code>
 391:    */
 392:   public void focusLost(FocusEvent event)
 393:   {
 394:     // TODO: Implement this properly.
 395:   }
 396: 
 397:   /**
 398:    * Moves the caret to the position specified in the <code>MouseEvent</code>.
 399:    * This will cause a selection if the dot and mark are different.
 400:    *
 401:    * @param event the <code>MouseEvent</code> from which to fetch the position
 402:    */
 403:   protected void moveCaret(MouseEvent event)
 404:   {
 405:     // FIXME: Implement this properly.
 406:   }
 407: 
 408:   /**
 409:    * Repositions the caret to the position specified in the
 410:    * <code>MouseEvent</code>.
 411:    *
 412:    * @param event the <code>MouseEvent</code> from which to fetch the position
 413:    */
 414:   protected void positionCaret(MouseEvent event)
 415:   {
 416:     // FIXME: Implement this properly.
 417:   }
 418: 
 419:   /**
 420:    * Deinstalls this <code>Caret</code> from the specified
 421:    * <code>JTextComponent</code>. This removes any listeners that have been
 422:    * registered by this <code>Caret</code>.
 423:    *
 424:    * @param c the text component from which to install this caret
 425:    */
 426:   public void deinstall(JTextComponent c)
 427:   {
 428:     textComponent.removeFocusListener(this);
 429:     textComponent.removeMouseListener(this);
 430:     textComponent.removeMouseMotionListener(this);
 431:     textComponent.getDocument().removeDocumentListener(documentListener);
 432:     documentListener = null;
 433:     textComponent.removePropertyChangeListener(propertyChangeListener);
 434:     propertyChangeListener = null;
 435:     textComponent = null;
 436:   }
 437: 
 438:   /**
 439:    * Installs this <code>Caret</code> on the specified
 440:    * <code>JTextComponent</code>. This registers a couple of listeners
 441:    * on the text component.
 442:    *
 443:    * @param c the text component on which to install this caret
 444:    */
 445:   public void install(JTextComponent c)
 446:   {
 447:     textComponent = c;
 448:     textComponent.addFocusListener(this);
 449:     textComponent.addMouseListener(this);
 450:     textComponent.addMouseMotionListener(this);
 451:     propertyChangeListener = new PropertyChangeHandler();
 452:     textComponent.addPropertyChangeListener(propertyChangeListener);
 453:     documentListener = new DocumentHandler();
 454:     textComponent.getDocument().addDocumentListener(documentListener);
 455:     repaint();
 456:   }
 457: 
 458:   /**
 459:    * Sets the current visual position of this <code>Caret</code>.
 460:    *
 461:    * @param p the Point to use for the saved location. May be <code>null</code>
 462:    *        to indicate that there is no visual location
 463:    */
 464:   public void setMagicCaretPosition(Point p)
 465:   {
 466:     magicCaretPosition = p;
 467:   }
 468: 
 469:   /**
 470:    * Returns the current visual position of this <code>Caret</code>.
 471:    *
 472:    * @return the current visual position of this <code>Caret</code>
 473:    *
 474:    * @see #setMagicCaretPosition
 475:    */
 476:   public Point getMagicCaretPosition()
 477:   {
 478:     return magicCaretPosition;
 479:   }
 480: 
 481:   /**
 482:    * Returns the current position of the <code>mark</code>. The
 483:    * <code>mark</code> marks the location in the <code>Document</code> that
 484:    * is the end of a selection. If there is no selection, the <code>mark</code>
 485:    * is the same as the <code>dot</code>.
 486:    *
 487:    * @return the current position of the mark
 488:    */
 489:   public int getMark()
 490:   {
 491:     return mark;
 492:   }
 493: 
 494:   private void handleHighlight()
 495:   {
 496:     Highlighter highlighter = textComponent.getHighlighter();
 497:     
 498:     if (highlighter == null)
 499:       return;
 500:     
 501:     int p0 = Math.min(dot, mark);
 502:     int p1 = Math.max(dot, mark);
 503:     
 504:     if (selectionVisible && p0 != p1)
 505:       {
 506:     try
 507:       {
 508:         if (highlightEntry == null)
 509:           highlightEntry = highlighter.addHighlight(p0, p1, getSelectionPainter());
 510:         else
 511:           highlighter.changeHighlight(highlightEntry, p0, p1);
 512:       }
 513:     catch (BadLocationException e)
 514:       {
 515:         // This should never happen.
 516:         throw new InternalError();
 517:       }
 518:       }
 519:     else
 520:       {
 521:     if (highlightEntry != null)
 522:       {
 523:         highlighter.removeHighlight(highlightEntry);
 524:         highlightEntry = null;
 525:       }
 526:       }
 527:   }
 528: 
 529:   /**
 530:    * Sets the visiblity state of the selection.
 531:    *
 532:    * @param v <code>true</code> if the selection should be visible,
 533:    *        <code>false</code> otherwise
 534:    */
 535:   public void setSelectionVisible(boolean v)
 536:   {
 537:     if (selectionVisible == v)
 538:       return;
 539:     
 540:     selectionVisible = v;
 541:     handleHighlight();
 542:     repaint();
 543:   }
 544: 
 545:   /**
 546:    * Returns <code>true</code> if the selection is currently visible,
 547:    * <code>false</code> otherwise.
 548:    *
 549:    * @return <code>true</code> if the selection is currently visible,
 550:    *         <code>false</code> otherwise
 551:    */
 552:   public boolean isSelectionVisible()
 553:   {
 554:     return selectionVisible;
 555:   }
 556: 
 557:   /**
 558:    * Causes the <code>Caret</code> to repaint itself.
 559:    */
 560:   protected final void repaint()
 561:   {
 562:     textComponent.repaint(this);
 563:   }
 564: 
 565:   /**
 566:    * Paints this <code>Caret</code> using the specified <code>Graphics</code>
 567:    * context.
 568:    *
 569:    * @param g the graphics context to use
 570:    */
 571:   public void paint(Graphics g)
 572:   {
 573:     if (textComponent == null)
 574:       return;
 575: 
 576:     int dot = getDot();
 577:     Rectangle rect = null;
 578: 
 579:     try
 580:       {
 581:     rect = textComponent.modelToView(dot);
 582:       }
 583:     catch (BadLocationException e)
 584:       {
 585:     // This should never happen as dot should be always valid.
 586:     return;
 587:       }
 588: 
 589:     if (rect == null)
 590:       return;
 591:     
 592:     // First we need to delete the old caret.
 593:     // FIXME: Implement deleting of old caret.
 594:     
 595:     // Now draw the caret on the new position if visible.
 596:     if (visible)
 597:       {
 598:     g.setColor(textComponent.getCaretColor());
 599:     g.drawLine(rect.x, rect.y, rect.x, rect.y + rect.height);
 600:       }
 601:   }
 602: 
 603:   /**
 604:    * Returns all registered event listeners of the specified type.
 605:    *
 606:    * @param listenerType the type of listener to return
 607:    *
 608:    * @return all registered event listeners of the specified type
 609:    */
 610:   public EventListener[] getListeners(Class listenerType)
 611:   {
 612:     return listenerList.getListeners(listenerType);
 613:   }
 614: 
 615:   /**
 616:    * Registers a {@link ChangeListener} that is notified whenever that state
 617:    * of this <code>Caret</code> changes.
 618:    *
 619:    * @param listener the listener to register to this caret
 620:    */
 621:   public void addChangeListener(ChangeListener listener)
 622:   {
 623:     listenerList.add(ChangeListener.class, listener);
 624:   }
 625: 
 626:   /**
 627:    * Removes a {@link ChangeListener} from the list of registered listeners.
 628:    *
 629:    * @param listener the listener to remove
 630:    */
 631:   public void removeChangeListener(ChangeListener listener)
 632:   {
 633:     listenerList.remove(ChangeListener.class, listener);
 634:   }
 635: 
 636:   /**
 637:    * Returns all registered {@link ChangeListener}s of this <code>Caret</code>.
 638:    *
 639:    * @return all registered {@link ChangeListener}s of this <code>Caret</code>
 640:    */
 641:   public ChangeListener[] getChangeListeners()
 642:   {
 643:     return (ChangeListener[]) getListeners(ChangeListener.class);
 644:   }
 645: 
 646:   /**
 647:    * Notifies all registered {@link ChangeListener}s that the state
 648:    * of this <code>Caret</code> has changed.
 649:    */
 650:   protected void fireStateChanged()
 651:   {
 652:     ChangeListener[] listeners = getChangeListeners();
 653: 
 654:     for (int index = 0; index < listeners.length; ++index)
 655:       listeners[index].stateChanged(changeEvent);
 656:   }
 657: 
 658:   /**
 659:    * Returns the <code>JTextComponent</code> on which this <code>Caret</code>
 660:    * is installed.
 661:    *
 662:    * @return the <code>JTextComponent</code> on which this <code>Caret</code>
 663:    *         is installed
 664:    */
 665:   protected final JTextComponent getComponent()
 666:   {
 667:     return textComponent;
 668:   }
 669: 
 670:   /**
 671:    * Returns the blink rate of this <code>Caret</code> in milliseconds.
 672:    * A value of <code>0</code> means that the caret does not blink.
 673:    *
 674:    * @return the blink rate of this <code>Caret</code> or <code>0</code> if
 675:    *         this caret does not blink
 676:    */
 677:   public int getBlinkRate()
 678:   {
 679:     return blinkRate;
 680:   }
 681: 
 682:   /**
 683:    * Sets the blink rate of this <code>Caret</code> in milliseconds.
 684:    * A value of <code>0</code> means that the caret does not blink.
 685:    *
 686:    * @param rate the new blink rate to set
 687:    */
 688:   public void setBlinkRate(int rate)
 689:   {
 690:     blinkRate = rate;
 691:   }
 692: 
 693:   /**
 694:    * Returns the current position of this <code>Caret</code> within the
 695:    * <code>Document</code>.
 696:    *
 697:    * @return the current position of this <code>Caret</code> within the
 698:    *         <code>Document</code>
 699:    */
 700:   public int getDot()
 701:   {
 702:     return dot;
 703:   }
 704: 
 705:   /**
 706:    * Moves the <code>dot</code> location without touching the
 707:    * <code>mark</code>. This is used when making a selection.
 708:    *
 709:    * @param dot the location where to move the dot
 710:    *
 711:    * @see #setDot(int)
 712:    */
 713:   public void moveDot(int dot)
 714:   {
 715:     this.dot = dot;
 716:     handleHighlight();
 717:     repaint();
 718:   }
 719: 
 720:   /**
 721:    * Sets the current position of this <code>Caret</code> within the
 722:    * <code>Document</code>. This also sets the <code>mark</code> to the
 723:    * new location.
 724:    *
 725:    * @param dot the new position to be set
 726:    *
 727:    * @see #moveDot(int)
 728:    */
 729:   public void setDot(int dot)
 730:   {
 731:     this.dot = dot;
 732:     this.mark = dot;
 733:     handleHighlight();
 734:     repaint();
 735:   }
 736: 
 737:   /**
 738:    * Returns <code>true</code> if this <code>Caret</code> is currently visible,
 739:    * and <code>false</code> if it is not.
 740:    *
 741:    * @return <code>true</code> if this <code>Caret</code> is currently visible,
 742:    *         and <code>false</code> if it is not
 743:    */
 744:   public boolean isVisible()
 745:   {
 746:     return visible;
 747:   }
 748: 
 749:   /**
 750:    * Sets the visibility state of the caret. <code>true</code> shows the
 751:    * <code>Caret</code>, <code>false</code> hides it.
 752:    *
 753:    * @param v the visibility to set
 754:    */  
 755:   public void setVisible(boolean v)
 756:   {
 757:     if (v != visible)
 758:       {
 759:         visible = v;
 760:         repaint();
 761:       }
 762:   }
 763: 
 764:   /**
 765:    * Returns the {@link Highlighter.HighlightPainter} that should be used
 766:    * to paint the selection.
 767:    *
 768:    * @return the {@link Highlighter.HighlightPainter} that should be used
 769:    *         to paint the selection
 770:    */
 771:   protected Highlighter.HighlightPainter getSelectionPainter()
 772:   {
 773:     return DefaultHighlighter.DefaultPainter;
 774:   }
 775: }