Source for javax.swing.tree.DefaultTreeCellEditor

   1: /* DefaultTreeCellEditor.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: 
  39: package javax.swing.tree;
  40: 
  41: import java.awt.Color;
  42: import java.awt.Component;
  43: import java.awt.Container;
  44: import java.awt.Dimension;
  45: import java.awt.Font;
  46: import java.awt.Graphics;
  47: import java.awt.Rectangle;
  48: import java.awt.event.ActionEvent;
  49: import java.awt.event.ActionListener;
  50: import java.awt.event.MouseEvent;
  51: import java.io.IOException;
  52: import java.io.ObjectInputStream;
  53: import java.io.ObjectOutputStream;
  54: import java.util.EventObject;
  55: 
  56: import javax.swing.DefaultCellEditor;
  57: import javax.swing.Icon;
  58: import javax.swing.JTextField;
  59: import javax.swing.JTree;
  60: import javax.swing.SwingUtilities;
  61: import javax.swing.Timer;
  62: import javax.swing.UIManager;
  63: import javax.swing.border.Border;
  64: import javax.swing.event.CellEditorListener;
  65: import javax.swing.event.EventListenerList;
  66: import javax.swing.event.TreeSelectionEvent;
  67: import javax.swing.event.TreeSelectionListener;
  68: 
  69: /**
  70:  * Participates in the tree cell editing.
  71:  * 
  72:  * @author Andrew Selkirk
  73:  * @author Audrius Meskauskas
  74:  */
  75: public class DefaultTreeCellEditor
  76:   implements ActionListener, TreeCellEditor, TreeSelectionListener
  77: {
  78:   /**
  79:    * This container that appears on the tree during editing session.
  80:    * It contains the editing component displays various other editor - 
  81:    * specific parts like editing icon. 
  82:    */
  83:   public class EditorContainer extends Container
  84:   {
  85:    /**
  86:     * Use v 1.5 serial version UID for interoperability.
  87:     */
  88:     static final long serialVersionUID = 6470339600449699810L;
  89:     
  90:     /**
  91:      * Creates an <code>EditorContainer</code> object.
  92:      */
  93:     public EditorContainer()
  94:     {
  95:       setLayout(null);
  96:     }
  97: 
  98:     /**
  99:      * This method only exists for API compatibility and is useless as it does
 100:      * nothing. It got probably introduced by accident.
 101:      */
 102:     public void EditorContainer()
 103:     {
 104:       // Do nothing here.
 105:     }
 106:    
 107:     /**
 108:      * Overrides Container.paint to paint the node's icon and use the selection
 109:      * color for the background.
 110:      * 
 111:      * @param g -
 112:      *          the specified Graphics window
 113:      */
 114:     public void paint(Graphics g)
 115:     {
 116:       // Paint editing icon.
 117:       if (editingIcon != null)
 118:         {
 119:           // From the previous version, the left margin is taken as half
 120:           // of the icon width.
 121:           int y = Math.max(0, (getHeight() - editingIcon.getIconHeight()) / 2);
 122:           editingIcon.paintIcon(this, g, 0, y);
 123:         }
 124:       // Paint border.
 125:       Color c = getBorderSelectionColor();
 126:       if (c != null)
 127:         {
 128:           g.setColor(c);
 129:           g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
 130:         }
 131:       super.paint(g);
 132:     }
 133: 
 134:     /**
 135:      * Lays out this Container, moving the editor component to the left
 136:      * (leaving place for the icon).
 137:      */
 138:     public void doLayout()
 139:     {
 140:       if (editingComponent != null)
 141:         {
 142:           editingComponent.getPreferredSize();
 143:           editingComponent.setBounds(offset, 0, getWidth() - offset,
 144:                                      getHeight());
 145:         }
 146:       }
 147: 
 148:     public Dimension getPreferredSize()
 149:     {
 150:       Dimension dim;
 151:       if (editingComponent != null)
 152:         {
 153:           dim = editingComponent.getPreferredSize();
 154:           dim.width += offset + 5;
 155:           if (renderer != null)
 156:             {
 157:               Dimension r = renderer.getPreferredSize();
 158:               dim.height = Math.max(dim.height, r.height);
 159:             }
 160:           if (editingIcon != null)
 161:             dim.height = Math.max(dim.height, editingIcon.getIconHeight());
 162:           dim.width = Math.max(100, dim.width);
 163:         }
 164:       else
 165:         dim = new Dimension(0, 0);
 166:       return dim;
 167:     }
 168:   }
 169: 
 170:   /**
 171:    * The default text field, used in the editing sessions.
 172:    */
 173:   public class DefaultTextField extends JTextField
 174:   {
 175:    /**
 176:     * Use v 1.5 serial version UID for interoperability.
 177:     */
 178:     static final long serialVersionUID = -6629304544265300143L; 
 179:     
 180:     /**
 181:      * The border of the text field.
 182:      */
 183:     protected Border border;
 184: 
 185:     /**
 186:      * Creates a <code>DefaultTextField</code> object.
 187:      *
 188:      * @param aBorder the border to use
 189:      */
 190:     public DefaultTextField(Border aBorder)
 191:     {
 192:       border = aBorder;
 193:     }
 194: 
 195:     /**
 196:      * Gets the font of this component.
 197:      * @return this component's font; if a font has not been set for 
 198:      * this component, the font of its parent is returned (if the parent
 199:      * is not null, otherwise null is returned). 
 200:      */
 201:     public Font getFont()
 202:     {
 203:       Font font = super.getFont();
 204:       if (font == null)
 205:         {
 206:           Component parent = getParent();
 207:           if (parent != null)
 208:             return parent.getFont();
 209:           return null;
 210:         }
 211:       return font;
 212:     }
 213: 
 214:     /**
 215:      * Returns the border of the text field.
 216:      *
 217:      * @return the border
 218:      */
 219:     public Border getBorder()
 220:     {
 221:       return border;
 222:     }
 223: 
 224:     /**
 225:      * Overrides JTextField.getPreferredSize to return the preferred size 
 226:      * based on current font, if set, or else use renderer's font.
 227:      * 
 228:      * @return the Dimension of this textfield.
 229:      */
 230:     public Dimension getPreferredSize()
 231:     {
 232:       Dimension size = super.getPreferredSize();
 233:       if (renderer != null && DefaultTreeCellEditor.this.getFont() == null)
 234:         {
 235:           size.height = renderer.getPreferredSize().height;
 236:         }
 237:       return renderer.getPreferredSize();
 238:     }
 239:   }
 240:   
 241:   private EventListenerList listenerList = new EventListenerList();
 242:   
 243:   /**
 244:    * Editor handling the editing.
 245:    */
 246:   protected TreeCellEditor realEditor;
 247: 
 248:   /**
 249:    * Renderer, used to get border and offsets from.
 250:    */
 251:   protected DefaultTreeCellRenderer renderer;
 252: 
 253:   /**
 254:    * Editing container, will contain the editorComponent.
 255:    */
 256:   protected Container editingContainer;
 257: 
 258:   /**
 259:    * Component used in editing, obtained from the editingContainer.
 260:    */
 261:   protected transient Component editingComponent;
 262: 
 263:   /**
 264:    * As of Java 2 platform v1.4 this field should no longer be used. 
 265:    * If you wish to provide similar behavior you should directly 
 266:    * override isCellEditable.
 267:    */
 268:   protected boolean canEdit;
 269: 
 270:   /**
 271:    * Used in editing. Indicates x position to place editingComponent.
 272:    */
 273:   protected transient int offset;
 274: 
 275:   /**
 276:    * JTree instance listening too.
 277:    */
 278:   protected transient JTree tree;
 279: 
 280:   /**
 281:    * Last path that was selected.
 282:    */
 283:   protected transient TreePath lastPath;
 284: 
 285:   /**
 286:    * Used before starting the editing session.
 287:    */
 288:   protected transient javax.swing.Timer timer;
 289: 
 290:   /**
 291:    * Row that was last passed into getTreeCellEditorComponent.
 292:    */
 293:   protected transient int lastRow;
 294: 
 295:   /**
 296:    * True if the border selection color should be drawn.
 297:    */
 298:   protected Color borderSelectionColor;
 299: 
 300:   /**
 301:    * Icon to use when editing.
 302:    */
 303:   protected transient Icon editingIcon;
 304: 
 305:   /**
 306:    * Font to paint with, null indicates font of renderer is to be used.
 307:    */
 308:   protected Font font;
 309:   
 310:   /**
 311:    * Helper field used to save the last path seen while the timer was
 312:    * running.
 313:    */
 314:     private TreePath tPath;
 315:     
 316:   /**
 317:    * Constructs a DefaultTreeCellEditor object for a JTree using the 
 318:    * specified renderer and a default editor. (Use this constructor 
 319:    * for normal editing.)
 320:    * 
 321:    * @param tree - a JTree object
 322:    * @param renderer - a DefaultTreeCellRenderer object
 323:    */
 324:   public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer)
 325:   {
 326:     this(tree, renderer, null);
 327:   }
 328: 
 329:   /**
 330:    * Constructs a DefaultTreeCellEditor  object for a JTree using the specified 
 331:    * renderer and the specified editor. (Use this constructor 
 332:    * for specialized editing.)
 333:    * 
 334:    * @param tree - a JTree object
 335:    * @param renderer - a DefaultTreeCellRenderer object
 336:    * @param editor - a TreeCellEditor object
 337:    */
 338:   public DefaultTreeCellEditor(JTree tree, DefaultTreeCellRenderer renderer,
 339:                                TreeCellEditor editor)
 340:   {
 341:     this.renderer = renderer;
 342:     realEditor = editor;
 343:     if (realEditor == null)
 344:       realEditor = createTreeCellEditor();
 345:     editingContainer = createContainer();
 346:     setTree(tree);
 347:     Color c = UIManager.getColor("Tree.editorBorderSelectionColor");
 348:     setBorderSelectionColor(c);
 349:   }
 350: 
 351:   /**
 352:    * Configures the editing component whenever it is null.
 353:    * 
 354:    * @param tree the tree to configure to component for.
 355:    * @param renderer the renderer used to set up the nodes
 356:    * @param editor the editor used 
 357:    */
 358:   private void configureEditingComponent(JTree tree,
 359:                                          DefaultTreeCellRenderer renderer,
 360:                                          TreeCellEditor editor)
 361:   {    
 362:     if (tree != null && lastPath != null)
 363:       {
 364:         Object val = lastPath.getLastPathComponent();
 365:         boolean isLeaf = tree.getModel().isLeaf(val);
 366:         boolean expanded = tree.isExpanded(lastPath);
 367:         determineOffset(tree, val, true, expanded, isLeaf, lastRow);
 368: 
 369:         // set up icon
 370:         if (isLeaf)
 371:           renderer.setIcon(renderer.getLeafIcon());
 372:         else if (expanded)
 373:           renderer.setIcon(renderer.getOpenIcon());
 374:         else
 375:           renderer.setIcon(renderer.getClosedIcon());
 376:         editingIcon = renderer.getIcon();
 377:         
 378:         editingComponent = getTreeCellEditorComponent(tree, val, true,
 379:                                                       expanded, isLeaf, lastRow);
 380:       }
 381:   }
 382:   
 383:   /**
 384:    * writeObject
 385:    * 
 386:    * @param value0
 387:    *          TODO
 388:    * @exception IOException
 389:    *              TODO
 390:    */
 391:   private void writeObject(ObjectOutputStream value0) throws IOException
 392:   {
 393:     // TODO
 394:   }
 395: 
 396:   /**
 397:    * readObject
 398:    * @param value0 TODO
 399:    * @exception IOException TODO
 400:    * @exception ClassNotFoundException TODO
 401:    */
 402:   private void readObject(ObjectInputStream value0)
 403:     throws IOException, ClassNotFoundException
 404:   {
 405:     // TODO
 406:   }
 407: 
 408:   /**
 409:    * Sets the color to use for the border.
 410:    * @param newColor - the new border color
 411:    */
 412:   public void setBorderSelectionColor(Color newColor)
 413:   {
 414:     this.borderSelectionColor = newColor;
 415:   }
 416: 
 417:   /**
 418:    * Returns the color the border is drawn.
 419:    * @return Color
 420:    */
 421:   public Color getBorderSelectionColor()
 422:   {
 423:     return borderSelectionColor;
 424:   }
 425: 
 426:   /**
 427:    * Sets the font to edit with. null indicates the renderers 
 428:    * font should be used. This will NOT override any font you have 
 429:    * set in the editor the receiver was instantied with. If null for 
 430:    * an editor was passed in, a default editor will be created that 
 431:    * will pick up this font.
 432:    * 
 433:    * @param font - the editing Font
 434:    */
 435:   public void setFont(Font font)
 436:   {
 437:     if (font != null)
 438:       this.font = font;
 439:     else
 440:       this.font = renderer.getFont();
 441:   }
 442: 
 443:   /**
 444:    * Gets the font used for editing.
 445:    * 
 446:    * @return the editing font
 447:    */
 448:   public Font getFont()
 449:   {
 450:     return font;
 451:   }
 452: 
 453:   /**
 454:    * Configures the editor. Passed onto the realEditor.
 455:    * Sets an initial value for the editor. This will cause 
 456:    * the editor to stopEditing and lose any partially edited value 
 457:    * if the editor is editing when this method is called. 
 458:    * Returns the component that should be added to the client's Component 
 459:    * hierarchy. Once installed in the client's hierarchy this component will 
 460:    * then be able to draw and receive user input. 
 461:    * 
 462:    * @param tree - the JTree that is asking the editor to edit; this parameter can be null
 463:    * @param value - the value of the cell to be edited
 464:    * @param isSelected - true is the cell is to be rendered with selection highlighting
 465:    * @param expanded - true if the node is expanded
 466:    * @param leaf - true if the node is a leaf node
 467:    * @param row - the row index of the node being edited
 468:    * 
 469:    * @return the component for editing
 470:    */
 471:   public Component getTreeCellEditorComponent(JTree tree, Object value,
 472:                                               boolean isSelected,
 473:                                               boolean expanded,
 474:                                               boolean leaf, int row)
 475:   {
 476:     setTree(tree);
 477:     lastRow = row;
 478:     determineOffset(tree, value, isSelected, expanded, leaf, row);
 479:     if (editingComponent != null)
 480:       editingContainer.remove(editingComponent);
 481: 
 482:     editingComponent = realEditor.getTreeCellEditorComponent(tree, value,
 483:                                                              isSelected,
 484:                                                              expanded, leaf,
 485:                                                              row);
 486:     Font f = getFont();
 487:     if (f == null)
 488:       {
 489:         if (renderer != null)
 490:           f = renderer.getFont();
 491:         if (f == null)
 492:           f = tree.getFont();
 493:       }
 494:     editingContainer.setFont(f);
 495:     prepareForEditing();
 496:     return editingContainer;
 497:   }
 498: 
 499:   /**
 500:    * Returns the value currently being edited (requests it from the
 501:    * {@link #realEditor}.
 502:    * 
 503:    * @return the value currently being edited
 504:    */
 505:   public Object getCellEditorValue()
 506:   {
 507:     return realEditor.getCellEditorValue();
 508:   }
 509:   
 510:   /**
 511:    * If the realEditor returns true to this message, prepareForEditing  
 512:    * is messaged and true is returned.
 513:    * 
 514:    * @param event - the event the editor should use to consider whether to 
 515:    * begin editing or not
 516:    * @return true if editing can be started
 517:    */
 518:   public boolean isCellEditable(EventObject event)
 519:   {
 520:     boolean ret = false;
 521:     boolean ed = false;
 522:     if (event != null)
 523:       {
 524:         if (event.getSource() instanceof JTree)
 525:           {
 526:             setTree((JTree) event.getSource());
 527:             if (event instanceof MouseEvent)
 528:               {
 529:                 MouseEvent me = (MouseEvent) event;
 530:                 TreePath path = tree.getPathForLocation(me.getX(), me.getY());
 531:                 ed = lastPath != null && path != null && lastPath.equals(path);
 532:                 if (path != null)
 533:                   {
 534:                     lastRow = tree.getRowForPath(path);
 535:                     Object val = path.getLastPathComponent();
 536:                     boolean isSelected = tree.isRowSelected(lastRow);
 537:                     boolean isExpanded = tree.isExpanded(path);
 538:                     TreeModel m = tree.getModel();
 539:                     boolean isLeaf = m.isLeaf(val);
 540:                     determineOffset(tree, val, isSelected, isExpanded, isLeaf,
 541:                                     lastRow);
 542:                   }
 543:               }
 544:           }
 545:       }
 546:     if (! realEditor.isCellEditable(event))
 547:       ret = false;
 548:     else 
 549:       {
 550:         if (canEditImmediately(event))
 551:           ret = true;
 552:         else if (ed && shouldStartEditingTimer(event))
 553:           startEditingTimer();
 554:         else if (timer != null && timer.isRunning())
 555:           timer.stop();
 556:       }
 557:     if (ret)
 558:       prepareForEditing();
 559:     return ret;
 560:         
 561:   }
 562: 
 563:   /**
 564:    * Messages the realEditor for the return value.
 565:    * 
 566:    * @param event -
 567:    *          the event the editor should use to start editing
 568:    * @return true if the editor would like the editing cell to be selected;
 569:    *         otherwise returns false
 570:    */
 571:   public boolean shouldSelectCell(EventObject event)
 572:   {
 573:     return true;
 574:   }
 575: 
 576:   /**
 577:    * If the realEditor will allow editing to stop, the realEditor
 578:    * is removed and true is returned, otherwise false is returned.
 579:    * @return true if editing was stopped; false otherwise
 580:    */
 581:   public boolean stopCellEditing()
 582:   {
 583:     boolean ret = false;
 584:     if (realEditor.stopCellEditing())
 585:       {
 586:         finish();
 587:         ret = true;
 588:       }
 589:     return ret;
 590:   }
 591: 
 592:   /**
 593:    * Messages cancelCellEditing to the realEditor and removes it
 594:    * from this instance.
 595:    */
 596:   public void cancelCellEditing()
 597:   {
 598:     realEditor.cancelCellEditing();
 599:     finish();
 600:   }
 601: 
 602:   private void finish()
 603:   {
 604:     if (editingComponent != null)
 605:       editingContainer.remove(editingComponent);
 606:     editingComponent = null;
 607:   }
 608: 
 609:   /**
 610:    * Adds a <code>CellEditorListener</code> object to this editor.
 611:    * 
 612:    * @param listener
 613:    *          the listener to add
 614:    */
 615:   public void addCellEditorListener(CellEditorListener listener)
 616:   {
 617:     realEditor.addCellEditorListener(listener);
 618:   }
 619: 
 620:   /**
 621:    * Removes a <code>CellEditorListener</code> object.
 622:    *
 623:    * @param listener the listener to remove
 624:    */
 625:   public void removeCellEditorListener(CellEditorListener listener)
 626:   {
 627:     realEditor.removeCellEditorListener(listener);
 628:   }
 629: 
 630:   /**
 631:    * Returns all added <code>CellEditorListener</code> objects to this editor.
 632:    *
 633:    * @return an array of listeners
 634:    *
 635:    * @since 1.4
 636:    */
 637:   public CellEditorListener[] getCellEditorListeners()
 638:   {
 639:     return (CellEditorListener[]) listenerList.getListeners(CellEditorListener.class);
 640:   }
 641: 
 642:   /**
 643:    * Resets lastPath.
 644:    * 
 645:    * @param e - the event that characterizes the change.
 646:    */
 647:   public void valueChanged(TreeSelectionEvent e)
 648:   {
 649:     if (tree != null)
 650:       {
 651:         if (tree.getSelectionCount() == 1)
 652:           lastPath = tree.getSelectionPath();
 653:         else
 654:           lastPath = null;
 655:       }
 656:     // TODO: We really should do the following here, but can't due
 657:     // to buggy DefaultTreeSelectionModel. This selection model
 658:     // should only fire if the selection actually changes.
 659: //    if (timer != null)
 660: //      timer.stop();
 661:   }
 662:   
 663:   /**
 664:    * Messaged when the timer fires.
 665:    * 
 666:    * @param e the event that characterizes the action.
 667:    */
 668:   public void actionPerformed(ActionEvent e)
 669:   {
 670:     if (tree != null && lastPath != null)
 671:       tree.startEditingAtPath(lastPath);
 672:   }
 673: 
 674:   /**
 675:    * Sets the tree currently editing for. This is needed to add a selection
 676:    * listener.
 677:    * 
 678:    * @param newTree -
 679:    *          the new tree to be edited
 680:    */
 681:   protected void setTree(JTree newTree)
 682:   {
 683:     if (tree != newTree)
 684:       {
 685:         if (tree != null)
 686:           tree.removeTreeSelectionListener(this);
 687:         tree = newTree;
 688:         if (tree != null)
 689:           tree.addTreeSelectionListener(this);
 690: 
 691:         if (timer != null)
 692:           timer.stop();
 693:       }
 694:   }
 695: 
 696:   /**
 697:    * Returns true if event is a MouseEvent and the click count is 1.
 698:    * 
 699:    * @param event - the event being studied
 700:    * @return true if editing should start
 701:    */
 702:   protected boolean shouldStartEditingTimer(EventObject event)
 703:   {
 704:     boolean ret = false;
 705:     if (event instanceof MouseEvent)
 706:       {
 707:         MouseEvent me = (MouseEvent) event;
 708:         ret = SwingUtilities.isLeftMouseButton(me) && me.getClickCount() == 1
 709:               && inHitRegion(me.getX(), me.getY());
 710:       }
 711:     return ret;
 712:   }
 713: 
 714:   /**
 715:    * Starts the editing timer (if one installed). 
 716:    */
 717:   protected void startEditingTimer()
 718:   {
 719:     if (timer == null)
 720:       {
 721:         timer = new Timer(1200, this);
 722:         timer.setRepeats(false);
 723:       }
 724:     timer.start();
 725:   }
 726: 
 727:   /**
 728:    * Returns true if event is null, or it is a MouseEvent with 
 729:    * a click count > 2 and inHitRegion returns true.
 730:    * 
 731:    * @param event - the event being studied
 732:    * @return true if event is null, or it is a MouseEvent with 
 733:    * a click count > 2 and inHitRegion returns true 
 734:    */
 735:   protected boolean canEditImmediately(EventObject event)
 736:   {
 737:     if (event == null || !(event instanceof MouseEvent) || (((MouseEvent) event).
 738:         getClickCount() > 2 && inHitRegion(((MouseEvent) event).getX(), 
 739:                                          ((MouseEvent) event).getY())))
 740:       return true;
 741:     return false;
 742:   }
 743: 
 744:   /**
 745:    * Returns true if the passed in location is a valid mouse location 
 746:    * to start editing from. This is implemented to return false if x is
 747:    * less than or equal to the width of the icon and icon 
 748:    * gap displayed by the renderer. In other words this returns true if 
 749:    * the user clicks over the text part displayed by the renderer, and 
 750:    * false otherwise.
 751:    * 
 752:    * @param x - the x-coordinate of the point
 753:    * @param y - the y-coordinate of the point
 754:    * 
 755:    * @return true if the passed in location is a valid mouse location
 756:    */
 757:   protected boolean inHitRegion(int x, int y)
 758:   {
 759:     Rectangle bounds = tree.getPathBounds(lastPath);
 760:     return bounds.contains(x, y);
 761:   }
 762: 
 763:   /**
 764:    * determineOffset
 765:    * @param tree -
 766:    * @param value - 
 767:    * @param isSelected - 
 768:    * @param expanded - 
 769:    * @param leaf - 
 770:    * @param row - 
 771:    */
 772:   protected void determineOffset(JTree tree, Object value, boolean isSelected,
 773:                                  boolean expanded, boolean leaf, int row)
 774:   {
 775:     if (renderer != null)
 776:       {
 777:         if (leaf)
 778:           editingIcon = renderer.getLeafIcon();
 779:         else if (expanded)
 780:           editingIcon = renderer.getOpenIcon();
 781:         else
 782:           editingIcon = renderer.getClosedIcon();
 783:         if (editingIcon != null)
 784:           offset = renderer.getIconTextGap() + editingIcon.getIconWidth();
 785:         else
 786:           offset = renderer.getIconTextGap();
 787:       }
 788:     else
 789:       {
 790:         editingIcon = null;
 791:         offset = 0;
 792:       }
 793:   }
 794: 
 795:   /**
 796:    * Invoked just before editing is to start. Will add the 
 797:    * editingComponent to the editingContainer.
 798:    */
 799:   protected void prepareForEditing()
 800:   {
 801:     if (editingComponent != null)
 802:       editingContainer.add(editingComponent);
 803:   }
 804: 
 805:   /**
 806:    * Creates the container to manage placement of editingComponent.
 807:    * 
 808:    * @return the container to manage the placement of the editingComponent.
 809:    */
 810:   protected Container createContainer()
 811:   {
 812:     return new DefaultTreeCellEditor.EditorContainer();
 813:   }
 814: 
 815:   /**
 816:    * This is invoked if a TreeCellEditor is not supplied in the constructor. 
 817:    * It returns a TextField editor.
 818:    * 
 819:    * @return a new TextField editor
 820:    */
 821:   protected TreeCellEditor createTreeCellEditor()
 822:   {
 823:     Border border = UIManager.getBorder("Tree.editorBorder");
 824:     JTextField tf = new DefaultTreeCellEditor.DefaultTextField(border);
 825:     DefaultCellEditor editor = new DefaultCellEditor(tf);
 826:     editor.setClickCountToStart(1);
 827:     realEditor = editor;
 828:     return editor;
 829:   }
 830: }