OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libjava/] [classpath/] [javax/] [swing/] [JTree.java] - Blame information for rev 772

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 772 jeremybenn
/* JTree.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;
39
 
40
import java.awt.Color;
41
import java.awt.Cursor;
42
import java.awt.Dimension;
43
import java.awt.Font;
44
import java.awt.FontMetrics;
45
import java.awt.Point;
46
import java.awt.Rectangle;
47
import java.awt.event.FocusListener;
48
import java.beans.PropertyChangeListener;
49
import java.io.Serializable;
50
import java.util.Enumeration;
51
import java.util.Hashtable;
52
import java.util.Iterator;
53
import java.util.Locale;
54
import java.util.Vector;
55
 
56
import javax.accessibility.Accessible;
57
import javax.accessibility.AccessibleAction;
58
import javax.accessibility.AccessibleComponent;
59
import javax.accessibility.AccessibleContext;
60
import javax.accessibility.AccessibleRole;
61
import javax.accessibility.AccessibleSelection;
62
import javax.accessibility.AccessibleState;
63
import javax.accessibility.AccessibleStateSet;
64
import javax.accessibility.AccessibleText;
65
import javax.accessibility.AccessibleValue;
66
import javax.swing.event.TreeExpansionEvent;
67
import javax.swing.event.TreeExpansionListener;
68
import javax.swing.event.TreeModelEvent;
69
import javax.swing.event.TreeModelListener;
70
import javax.swing.event.TreeSelectionEvent;
71
import javax.swing.event.TreeSelectionListener;
72
import javax.swing.event.TreeWillExpandListener;
73
import javax.swing.plaf.TreeUI;
74
import javax.swing.text.Position;
75
import javax.swing.tree.DefaultMutableTreeNode;
76
import javax.swing.tree.DefaultTreeModel;
77
import javax.swing.tree.DefaultTreeSelectionModel;
78
import javax.swing.tree.ExpandVetoException;
79
import javax.swing.tree.TreeCellEditor;
80
import javax.swing.tree.TreeCellRenderer;
81
import javax.swing.tree.TreeModel;
82
import javax.swing.tree.TreeNode;
83
import javax.swing.tree.TreePath;
84
import javax.swing.tree.TreeSelectionModel;
85
 
86
public class JTree extends JComponent implements Scrollable, Accessible
87
{
88
 
89
  /**
90
   * This class implements accessibility support for the JTree class. It
91
   * provides an implementation of the Java Accessibility API appropriate
92
   * to tree user-interface elements.
93
   */
94
  protected class AccessibleJTree extends JComponent.AccessibleJComponent
95
      implements AccessibleSelection, TreeSelectionListener, TreeModelListener,
96
      TreeExpansionListener
97
  {
98
 
99
    /**
100
     * This class implements accessibility support for the JTree child. It provides
101
     * an implementation of the Java Accessibility API appropriate to tree nodes.
102
     */
103
    protected class AccessibleJTreeNode extends AccessibleContext
104
       implements Accessible, AccessibleComponent, AccessibleSelection,
105
       AccessibleAction
106
    {
107
 
108
      private JTree tree;
109
      private TreePath tp;
110
      private Accessible acc;
111
      private AccessibleStateSet states;
112
      private Vector selectionList;
113
      private Vector actionList;
114
      private TreeModel mod;
115
      private Cursor cursor;
116
 
117
      /**
118
       * Constructs an AccessibleJTreeNode
119
       *
120
       * @param t - the current tree
121
       * @param p - the current path to be dealt with
122
       * @param ap - the accessible object to use
123
       */
124
      public AccessibleJTreeNode(JTree t, TreePath p, Accessible ap)
125
      {
126
        states = new AccessibleStateSet();
127
        selectionList = new Vector();
128
        actionList = new Vector();
129
        mod = tree.getModel();
130
        cursor = JTree.this.getCursor();
131
 
132
        tree = t;
133
        tp = p;
134
        acc = ap;
135
 
136
        // Add all the children of this path that may already be
137
        // selected to the selection list.
138
        TreePath[] selected = tree.getSelectionPaths();
139
        for (int i = 0; i < selected.length; i++)
140
          {
141
            TreePath sel = selected[i];
142
            if ((sel.getParentPath()).equals(tp))
143
              selectionList.add(sel);
144
          }
145
 
146
        // Add all the actions available for a node to
147
        // the action list.
148
        actionList.add("EXPAND");
149
        actionList.add("COLLAPSE");
150
        actionList.add("EDIT");
151
        actionList.add("SELECT");
152
        actionList.add("DESELECT");
153
      }
154
 
155
      /**
156
       * Adds the specified selected item in the object to the object's
157
       * selection.
158
       *
159
       * @param i - the i-th child of this node.
160
       */
161
      public void addAccessibleSelection(int i)
162
      {
163
        if (mod != null)
164
          {
165
            Object child = mod.getChild(tp.getLastPathComponent(), i);
166
            if (child != null)
167
              {
168
                if (!states.contains(AccessibleState.MULTISELECTABLE))
169
                  clearAccessibleSelection();
170
                selectionList.add(child);
171
                tree.addSelectionPath(tp.pathByAddingChild(child));
172
              }
173
          }
174
      }
175
 
176
      /**
177
       * Adds the specified focus listener to receive focus events
178
       * from this component.
179
       *
180
       * @param l - the new focus listener
181
       */
182
      public void addFocusListener(FocusListener l)
183
      {
184
        tree.addFocusListener(l);
185
      }
186
 
187
      /**
188
       * Add a PropertyChangeListener to the listener list.
189
       *
190
       * @param l - the new property change listener
191
       */
192
      public void addPropertyChangeListener(PropertyChangeListener l)
193
      {
194
        // Nothing to do here.
195
      }
196
 
197
      /**
198
       * Clears the selection in the object, so that nothing in the
199
       * object is selected.
200
       */
201
      public void clearAccessibleSelection()
202
      {
203
        selectionList.clear();
204
      }
205
 
206
      /**
207
       * Checks whether the specified point is within this object's
208
       * bounds, where the point's x and y coordinates are defined to be
209
       * relative to the coordinate system of the object.
210
       *
211
       * @param p - the point to check
212
       * @return true if p is in the bounds
213
       */
214
      public boolean contains(Point p)
215
      {
216
        return getBounds().contains(p);
217
      }
218
 
219
      /**
220
       * Perform the specified Action on the tree node.
221
       *
222
       * @param i - the i-th action to perform
223
       * @return true if the the action was performed; else false.
224
       */
225
      public boolean doAccessibleAction(int i)
226
      {
227
        if (i >= actionList.size() || i < 0)
228
          return false;
229
 
230
        if (actionList.get(i).equals("EXPAND"))
231
          tree.expandPath(tp);
232
        else if (actionList.get(i).equals("COLLAPSE"))
233
          tree.collapsePath(tp);
234
        else if (actionList.get(i).equals("SELECT"))
235
          tree.addSelectionPath(tp);
236
        else if (actionList.get(i).equals("DESELECT"))
237
          tree.removeSelectionPath(tp);
238
        else if (actionList.get(i).equals("EDIT"))
239
          tree.startEditingAtPath(tp);
240
        else
241
          return false;
242
        return true;
243
      }
244
 
245
      /**
246
       * Get the AccessibleAction associated with this object.
247
       *
248
       * @return the action
249
       */
250
      public AccessibleAction getAccessibleAction()
251
      {
252
        return this;
253
      }
254
 
255
      /**
256
       * Returns the number of accessible actions available in this tree node.
257
       *
258
       * @return the number of actions
259
       */
260
      public int getAccessibleActionCount()
261
      {
262
        return actionList.size();
263
      }
264
 
265
      /**
266
       * Return a description of the specified action of the tree node.
267
       *
268
       * @param i - the i-th action's description
269
       * @return a description of the action
270
       */
271
      public String getAccessibleActionDescription(int i)
272
      {
273
        if (i < 0 || i >= actionList.size())
274
          return (actionList.get(i)).toString();
275
        return super.getAccessibleDescription();
276
      }
277
 
278
      /**
279
       * Returns the Accessible child, if one exists, contained at the
280
       * local coordinate Point.
281
       *
282
       * @param p - the point of the accessible
283
       * @return the accessible at point p if it exists
284
       */
285
      public Accessible getAccessibleAt(Point p)
286
      {
287
        TreePath acc = tree.getClosestPathForLocation(p.x, p.y);
288
        if (acc != null)
289
          return new AccessibleJTreeNode(tree, acc, this);
290
        return null;
291
      }
292
 
293
      /**
294
       * Return the specified Accessible child of the object.
295
       *
296
       * @param i - the i-th child of the current path
297
       * @return the child if it exists
298
       */
299
      public Accessible getAccessibleChild(int i)
300
      {
301
        if (mod != null)
302
          {
303
            Object child = mod.getChild(tp.getLastPathComponent(), i);
304
            if (child != null)
305
              return new AccessibleJTreeNode(tree, tp.pathByAddingChild(child),
306
                                             acc);
307
          }
308
        return null;
309
      }
310
 
311
      /**
312
       * Returns the number of accessible children in the object.
313
       *
314
       * @return the number of children the current node has
315
       */
316
      public int getAccessibleChildrenCount()
317
      {
318
        TreeModel mod = getModel();
319
        if (mod != null)
320
          return mod.getChildCount(tp.getLastPathComponent());
321
        return 0;
322
      }
323
 
324
      /**
325
       * Get the AccessibleComponent associated with this object.
326
       *
327
       * @return the accessible component if it is supported.
328
       */
329
      public AccessibleComponent getAccessibleComponent()
330
      {
331
        return this;
332
      }
333
 
334
      /**
335
       * Get the AccessibleContext associated with this tree node.
336
       *
337
       * @return an instance of this class
338
       */
339
      public AccessibleContext getAccessibleContext()
340
      {
341
        return this;
342
      }
343
 
344
      /**
345
       * Get the accessible description of this object.
346
       *
347
       * @return the accessible description
348
       */
349
      public String getAccessibleDescription()
350
      {
351
        return super.getAccessibleDescription();
352
      }
353
 
354
      /**
355
       * Get the index of this object in its accessible parent.
356
       *
357
       * @return the index of this in the parent.
358
       */
359
      public int getAccessibleIndexInParent()
360
      {
361
        AccessibleContext parent = getAccessibleParent().getAccessibleContext();
362
        if (parent != null)
363
          for (int i = 0; i < parent.getAccessibleChildrenCount(); i++)
364
            {
365
              if ((parent.getAccessibleChild(i)).equals(this))
366
                return i;
367
            }
368
        return -1;
369
      }
370
 
371
      /**
372
       * Get the accessible name of this object.
373
       *
374
       * @return the accessible name
375
       */
376
      public String getAccessibleName()
377
      {
378
        return super.getAccessibleName();
379
      }
380
 
381
      /**
382
       * Get the Accessible parent of this object.
383
       *
384
       * @return the accessible parent if it exists.
385
       */
386
      public Accessible getAccessibleParent()
387
      {
388
        return super.getAccessibleParent();
389
      }
390
 
391
      /**
392
       * Get the role of this object.
393
       *
394
       * @return the accessible role
395
       */
396
      public AccessibleRole getAccessibleRole()
397
      {
398
        return AccessibleJTree.this.getAccessibleRole();
399
      }
400
 
401
      /**
402
       * Get the AccessibleSelection associated with this object if one exists.
403
       *
404
       * @return the accessible selection for this.
405
       */
406
      public AccessibleSelection getAccessibleSelection()
407
      {
408
        return this;
409
      }
410
 
411
      /**
412
       * Returns an Accessible representing the specified selected item
413
       * in the object.
414
       *
415
       * @return the accessible representing a certain selected item.
416
       */
417
      public Accessible getAccessibleSelection(int i)
418
      {
419
        if (i > 0 && i < getAccessibleSelectionCount())
420
            return new AccessibleJTreeNode(tree,
421
                  tp.pathByAddingChild(selectionList.get(i)), acc);
422
        return null;
423
      }
424
 
425
      /**
426
       * Returns the number of items currently selected.
427
       *
428
       * @return the number of items selected.
429
       */
430
      public int getAccessibleSelectionCount()
431
      {
432
        return selectionList.size();
433
      }
434
 
435
      /**
436
       * Get the state set of this object.
437
       *
438
       * @return the state set for this object
439
       */
440
      public AccessibleStateSet getAccessibleStateSet()
441
      {
442
        if (isVisible())
443
          states.add(AccessibleState.VISIBLE);
444
        if (tree.isCollapsed(tp))
445
          states.add(AccessibleState.COLLAPSED);
446
        if (tree.isEditable())
447
          states.add(AccessibleState.EDITABLE);
448
        if (mod != null &&
449
            !mod.isLeaf(tp.getLastPathComponent()))
450
          states.add(AccessibleState.EXPANDABLE);
451
        if (tree.isExpanded(tp))
452
          states.add(AccessibleState.EXPANDED);
453
        if (isFocusable())
454
          states.add(AccessibleState.FOCUSABLE);
455
        if (hasFocus())
456
          states.add(AccessibleState.FOCUSED);
457
        if (tree.getSelectionModel().getSelectionMode() !=
458
          TreeSelectionModel.SINGLE_TREE_SELECTION)
459
          states.add(AccessibleState.MULTISELECTABLE);
460
        if (tree.isOpaque())
461
          states.add(AccessibleState.OPAQUE);
462
        if (tree.isPathSelected(tp))
463
          states.add(AccessibleState.SELECTED);
464
        if (isShowing())
465
          states.add(AccessibleState.SHOWING);
466
 
467
        states.add(AccessibleState.SELECTABLE);
468
        return states;
469
      }
470
 
471
      /**
472
       * Get the AccessibleText associated with this object if one exists.
473
       *
474
       * @return the accessible text
475
       */
476
      public AccessibleText getAccessibleText()
477
      {
478
        return super.getAccessibleText();
479
      }
480
 
481
      /**
482
       * Get the AccessibleValue associated with this object if one exists.
483
       *
484
       * @return the accessible value if it exists
485
       */
486
      public AccessibleValue getAccessibleValue()
487
      {
488
        return super.getAccessibleValue();
489
      }
490
 
491
      /**
492
       * Get the background color of this object.
493
       *
494
       * @return the color of the background.
495
       */
496
      public Color getBackground()
497
      {
498
        return tree.getBackground();
499
      }
500
 
501
      /**
502
       * Gets the bounds of this object in the form of a Rectangle object.
503
       *
504
       * @return the bounds of the current node.
505
       */
506
      public Rectangle getBounds()
507
      {
508
        return tree.getPathBounds(tp);
509
      }
510
 
511
      /**
512
       * Gets the Cursor of this object.
513
       *
514
       * @return the cursor for the current node
515
       */
516
      public Cursor getCursor()
517
      {
518
        return cursor;
519
      }
520
 
521
      /**
522
       * Gets the Font of this object.
523
       *
524
       * @return the font for the current node
525
       */
526
      public Font getFont()
527
      {
528
        return tree.getFont();
529
      }
530
 
531
      /**
532
       * Gets the FontMetrics of this object.
533
       *
534
       * @param f - the current font.
535
       * @return the font metrics for the given font.
536
       */
537
      public FontMetrics getFontMetrics(Font f)
538
      {
539
        return tree.getFontMetrics(f);
540
      }
541
 
542
      /**
543
       * Get the foreground color of this object.
544
       *
545
       * @return the foreground for this object.
546
       */
547
      public Color getForeground()
548
      {
549
        return tree.getForeground();
550
      }
551
 
552
      /**
553
       * Gets the locale of the component.
554
       *
555
       * @return the locale of the component.
556
       */
557
      public Locale getLocale()
558
      {
559
        return tree.getLocale();
560
      }
561
 
562
      /**
563
       * Gets the location of the object relative to the
564
       * parent in the form of a point specifying the object's
565
       * top-left corner in the screen's coordinate space.
566
       *
567
       * @return the location of the current node.
568
       */
569
      public Point getLocation()
570
      {
571
        return getLocationInJTree();
572
      }
573
 
574
      /**
575
       * Returns the location in the tree.
576
       *
577
       * @return the location in the JTree.
578
       */
579
      protected Point getLocationInJTree()
580
      {
581
        Rectangle bounds = tree.getPathBounds(tp);
582
        return new Point(bounds.x, bounds.y);
583
      }
584
 
585
      /**
586
       * Returns the location of the object on the screen.
587
       *
588
       * @return the location of the object on the screen.
589
       */
590
      public Point getLocationOnScreen()
591
      {
592
        Point loc = getLocation();
593
        SwingUtilities.convertPointToScreen(loc, tree);
594
        return loc;
595
      }
596
 
597
      /**
598
       * Returns the size of this object in the form of a Dimension object.
599
       *
600
       * @return the size of the object
601
       */
602
      public Dimension getSize()
603
      {
604
        Rectangle b = getBounds();
605
        return b.getSize();
606
      }
607
 
608
      /**
609
       * Returns true if the current child of this object is selected.
610
       *
611
       * @param i - the child of the current node
612
       * @return true if the child is selected.
613
       */
614
      public boolean isAccessibleChildSelected(int i)
615
      {
616
        Object child = mod.getChild(tp.getLastPathComponent(), i);
617
        if (child != null)
618
          return tree.isPathSelected(tp.pathByAddingChild(child));
619
        return false;
620
      }
621
 
622
      /**
623
       * Determines if the object is enabled.
624
       *
625
       * @return true if the tree is enabled
626
       */
627
      public boolean isEnabled()
628
      {
629
        return tree.isEnabled();
630
      }
631
 
632
      /**
633
       * Returns whether this object can accept focus or not.
634
       *
635
       * @return true, it is always focus traversable
636
       */
637
      public boolean isFocusTraversable()
638
      {
639
        return true;
640
      }
641
 
642
      /**
643
       * Determines if the object is showing.
644
       *
645
       * @return true if the object is visible and the
646
       * parent is visible.
647
       */
648
      public boolean isShowing()
649
      {
650
        return isVisible() && tree.isShowing();
651
      }
652
 
653
      /**
654
       * Determines if the object is visible.
655
       *
656
       * @return true if the object is visible.
657
       */
658
      public boolean isVisible()
659
      {
660
        return tree.isVisible(tp);
661
      }
662
 
663
      /**
664
       * Removes the specified selected item in the object from the
665
       * object's selection.
666
       *
667
       * @param i - the specified item to remove
668
       */
669
      public void removeAccessibleSelection(int i)
670
      {
671
        if (mod != null)
672
          {
673
            Object child = mod.getChild(tp.getLastPathComponent(), i);
674
            if (child != null)
675
              {
676
                if (!states.contains(AccessibleState.MULTISELECTABLE))
677
                  clearAccessibleSelection();
678
                if (selectionList.contains(child))
679
                  {
680
                    selectionList.remove(child);
681
                    tree.removeSelectionPath(tp.pathByAddingChild(child));
682
                  }
683
              }
684
          }
685
      }
686
 
687
      /**
688
       * Removes the specified focus listener so it no longer receives focus
689
       * events from this component.
690
       *
691
       * @param l - the focus listener to remove
692
       */
693
      public void removeFocusListener(FocusListener l)
694
      {
695
        tree.removeFocusListener(l);
696
      }
697
 
698
      /**
699
       * Remove a PropertyChangeListener from the listener list.
700
       *
701
       * @param l - the property change listener to remove.
702
       */
703
      public void removePropertyChangeListener(PropertyChangeListener l)
704
      {
705
        // Nothing to do here.
706
      }
707
 
708
      /**
709
       * Requests focus for this object.
710
       */
711
      public void requestFocus()
712
      {
713
        tree.requestFocus();
714
      }
715
 
716
      /**
717
       * Causes every selected item in the object to be selected if the object
718
       * supports multiple selections.
719
       */
720
      public void selectAllAccessibleSelection()
721
      {
722
        Object parent = tp.getLastPathComponent();
723
        if (mod != null)
724
          {
725
            for (int i = 0; i < mod.getChildCount(parent); i++)
726
              {
727
                Object child = mod.getChild(parent, i);
728
                if (child != null)
729
                  {
730
                    if (!states.contains(AccessibleState.MULTISELECTABLE))
731
                      clearAccessibleSelection();
732
                    if (selectionList.contains(child))
733
                      {
734
                        selectionList.add(child);
735
                        tree.addSelectionPath(tp.pathByAddingChild(child));
736
                      }
737
                  }
738
              }
739
          }
740
      }
741
 
742
      /**
743
       * Set the accessible description of this object.
744
       *
745
       * @param s - the string to set the accessible description to.
746
       */
747
      public void setAccessibleDescription(String s)
748
      {
749
        super.setAccessibleDescription(s);
750
      }
751
 
752
      /**
753
       * Set the localized accessible name of this object.
754
       *
755
       * @param s - the string to set the accessible name to.
756
       */
757
      public void setAccessibleName(String s)
758
      {
759
        super.setAccessibleName(s);
760
      }
761
 
762
      /**
763
       * Set the background color of this object.
764
       *
765
       * @param c - the color to set the background to.
766
       */
767
      public void setBackground(Color c)
768
      {
769
        // Nothing to do here.
770
      }
771
 
772
      /**
773
       * Sets the bounds of this object in the form of a Rectangle object.
774
       *
775
       * @param r - the bounds to set the object o
776
       */
777
      public void setBounds(Rectangle r)
778
      {
779
        // Nothing to do here.
780
      }
781
 
782
      /**
783
       * Sets the Cursor of this object.
784
       *
785
       * @param c - the new cursor
786
       */
787
      public void setCursor(Cursor c)
788
      {
789
        cursor = c;
790
      }
791
 
792
      /**
793
       * Sets the enabled state of the object.
794
       *
795
       * @param b - boolean to enable or disable object
796
       */
797
      public void setEnabled(boolean b)
798
      {
799
         // Nothing to do here.
800
      }
801
 
802
      /**
803
       * Sets the Font of this object.
804
       *
805
       * @param f - the new font.
806
       */
807
      public void setFont(Font f)
808
      {
809
         // Nothing to do here.
810
      }
811
 
812
      /**
813
       * Sets the foreground color of this object.
814
       *
815
       * @param c - the new foreground color.
816
       */
817
      public void setForeground(Color c)
818
      {
819
        // Nothing to do here.
820
      }
821
 
822
      /**
823
       * Sets the location of the object relative to the parent.
824
       *
825
       * @param p - the new location for the object.
826
       */
827
      public void setLocation(Point p)
828
      {
829
        // Nothing to do here.
830
      }
831
 
832
      /**
833
       * Resizes this object so that it has width and height.
834
       *
835
       * @param d - the new size for the object.
836
       */
837
      public void setSize(Dimension d)
838
      {
839
        // Nothing to do here.
840
      }
841
 
842
      /**
843
       * Sets the visible state of the object.
844
       *
845
       * @param b - sets the objects visibility.
846
       */
847
      public void setVisible(boolean b)
848
      {
849
        // Nothing to do here.
850
      }
851
    }
852
 
853
    /**
854
     * Constructor
855
     */
856
    public AccessibleJTree()
857
    {
858
      // Nothing to do here.
859
    }
860
 
861
    /**
862
     * Adds the specified selected item in the object to the object's selection.
863
     *
864
     * @param i - the row to add to the tree's selection
865
     */
866
    public void addAccessibleSelection(int i)
867
    {
868
      addSelectionInterval(i, i);
869
    }
870
 
871
    /**
872
     * Clears the selection in the object, so that nothing in the object is selected.
873
     */
874
    public void clearAccessibleSelection()
875
    {
876
      clearSelection();
877
    }
878
 
879
    /**
880
     * Fire a visible data property change notification.
881
     */
882
    public void fireVisibleDataPropertyChange()
883
    {
884
      treeDidChange();
885
    }
886
 
887
    /**
888
     * Returns the Accessible child, if one exists, contained at the local
889
     * coordinate Point.
890
     *
891
     * @param p - the point of the accessible to get.
892
     * @return the accessible at point p.
893
     */
894
    public Accessible getAccessibleAt(Point p)
895
    {
896
      TreePath tp = getClosestPathForLocation(p.x, p.y);
897
      if (tp != null)
898
        return new AccessibleJTreeNode(JTree.this, tp, null);
899
      return null;
900
    }
901
 
902
    /**
903
     * Return the nth Accessible child of the object.
904
     *
905
     * @param i - the accessible child to get
906
     * @return the i-th child
907
     */
908
    public Accessible getAccessibleChild(int i)
909
    {
910
      return null;
911
    }
912
 
913
    /**
914
     * Returns the number of top-level children nodes of this JTree.
915
     *
916
     * @return the number of top-level children
917
     */
918
    public int getAccessibleChildrenCount()
919
    {
920
      TreeModel model = getModel();
921
      if (model != null)
922
        return model.getChildCount(model.getRoot());
923
      return 0;
924
    }
925
 
926
    /**
927
     * Get the index of this object in its accessible parent.
928
     *
929
     * @return the index of this object.
930
     */
931
    public int getAccessibleIndexInParent()
932
    {
933
      return 0;
934
    }
935
 
936
    /**
937
     * Get the role of this object.
938
     *
939
     * @return the role of this object
940
     */
941
    public AccessibleRole getAccessibleRole()
942
    {
943
      return AccessibleRole.TREE;
944
    }
945
 
946
    /**
947
     * Get the AccessibleSelection associated with this object.
948
     *
949
     * @return the accessible selection of the tree
950
     */
951
    public AccessibleSelection getAccessibleSelection()
952
    {
953
      TreeModel mod = getModel();
954
      if (mod != null)
955
        return (new AccessibleJTreeNode(JTree.this,
956
                  new TreePath(mod.getRoot()), null)).getAccessibleSelection();
957
      return null;
958
    }
959
 
960
    /**
961
     * Returns an Accessible representing the specified selected item in the object.
962
     *
963
     * @return the i-th accessible in the selection
964
     */
965
    public Accessible getAccessibleSelection(int i)
966
    {
967
      TreeModel mod = getModel();
968
      if (mod != null)
969
        return (new AccessibleJTreeNode(JTree.this,
970
                  new TreePath(mod.getRoot()), null)).getAccessibleSelection(i);
971
      return null;
972
    }
973
 
974
    /**
975
     * Returns the number of items currently selected.
976
     *
977
     * @return the number of selected accessibles.
978
     */
979
    public int getAccessibleSelectionCount()
980
    {
981
      return getSelectionCount();
982
    }
983
 
984
    /**
985
     * Returns true if the current child of this object is selected.
986
     *
987
     * @param i - the child of this object
988
     * @return true if the i-th child is selected.
989
     */
990
    public boolean isAccessibleChildSelected(int i)
991
    {
992
      // Nothing to do here.
993
      return false;
994
    }
995
 
996
    /**
997
     * Removes the specified selected item in the object from the object's
998
     * selection.
999
     *
1000
     * @param i - the i-th selected item to remove
1001
     */
1002
    public void removeAccessibleSelection(int i)
1003
    {
1004
      removeSelectionInterval(i, i);
1005
    }
1006
 
1007
    /**
1008
     * Causes every selected item in the object to be selected if the object
1009
     * supports multiple selections.
1010
     */
1011
    public void selectAllAccessibleSelection()
1012
    {
1013
      if (getSelectionModel().getSelectionMode() !=
1014
        TreeSelectionModel.SINGLE_TREE_SELECTION)
1015
      addSelectionInterval(0, getVisibleRowCount());
1016
    }
1017
 
1018
    /**
1019
     * Tree Collapsed notification
1020
     *
1021
     * @param e - the event
1022
     */
1023
    public void treeCollapsed(TreeExpansionEvent e)
1024
    {
1025
      fireTreeCollapsed(e.getPath());
1026
    }
1027
 
1028
    /**
1029
     * Tree Model Expansion notification.
1030
     *
1031
     * @param e - the event
1032
     */
1033
    public void treeExpanded(TreeExpansionEvent e)
1034
    {
1035
      fireTreeExpanded(e.getPath());
1036
    }
1037
 
1038
    /**
1039
     * Tree Model Node change notification.
1040
     *
1041
     * @param e - the event
1042
     */
1043
    public void treeNodesChanged(TreeModelEvent e)
1044
    {
1045
      // Nothing to do here.
1046
    }
1047
 
1048
    /**
1049
     * Tree Model Node change notification.
1050
     *
1051
     * @param e - the event
1052
     */
1053
    public void treeNodesInserted(TreeModelEvent e)
1054
    {
1055
      // Nothing to do here.
1056
    }
1057
 
1058
    /**
1059
     * Tree Model Node change notification.
1060
     *
1061
     * @param e - the event
1062
     */
1063
    public void treeNodesRemoved(TreeModelEvent e)
1064
    {
1065
      // Nothing to do here.
1066
    }
1067
 
1068
    /**
1069
     * Tree Model structure change change notification.
1070
     *
1071
     * @param e - the event
1072
     */
1073
    public void treeStructureChanged(TreeModelEvent e)
1074
    {
1075
      // Nothing to do here.
1076
    }
1077
 
1078
    /**
1079
     * Tree Selection Listener value change method.
1080
     *
1081
     * @param e - the event
1082
     */
1083
    public void valueChanged(TreeSelectionEvent e)
1084
    {
1085
      fireValueChanged(e);
1086
    }
1087
  }
1088
 
1089
  public static class DynamicUtilTreeNode extends DefaultMutableTreeNode
1090
  {
1091
    protected Object childValue;
1092
 
1093
    protected boolean loadedChildren;
1094
 
1095
    /**
1096
     * Currently not set or used by this class. It might be set and used in
1097
     * later versions of this class.
1098
     */
1099
    protected boolean hasChildren;
1100
 
1101
    public DynamicUtilTreeNode(Object value, Object children)
1102
    {
1103
      super(value);
1104
      childValue = children;
1105
      loadedChildren = false;
1106
    }
1107
 
1108
    public int getChildCount()
1109
    {
1110
      loadChildren();
1111
      return super.getChildCount();
1112
    }
1113
 
1114
    protected void loadChildren()
1115
    {
1116
      if (!loadedChildren)
1117
        {
1118
          createChildren(this, childValue);
1119
          loadedChildren = true;
1120
        }
1121
    }
1122
 
1123
    public Enumeration children()
1124
    {
1125
      loadChildren();
1126
      return super.children();
1127
    }
1128
 
1129
    /**
1130
     * Returns the child node at position <code>pos</code>. Subclassed
1131
     * here to load the children if necessary.
1132
     *
1133
     * @param pos the position of the child node to fetch
1134
     *
1135
     * @return the childnode at the specified position
1136
     */
1137
    public TreeNode getChildAt(int pos)
1138
    {
1139
      loadChildren();
1140
      return super.getChildAt(pos);
1141
    }
1142
 
1143
    public boolean isLeaf()
1144
    {
1145
      return childValue == null || !(childValue instanceof Hashtable
1146
          || childValue instanceof Vector
1147
          || childValue.getClass().isArray());
1148
    }
1149
 
1150
    public static void createChildren(DefaultMutableTreeNode parent,
1151
                                      Object children)
1152
    {
1153
      if (children instanceof Hashtable)
1154
        {
1155
          Hashtable tab = (Hashtable) children;
1156
          Enumeration e = tab.keys();
1157
          while (e.hasMoreElements())
1158
            {
1159
              Object key = e.nextElement();
1160
              Object val = tab.get(key);
1161
              parent.add(new DynamicUtilTreeNode(key, val));
1162
            }
1163
        }
1164
      else if (children instanceof Vector)
1165
        {
1166
          Iterator i = ((Vector) children).iterator();
1167
          while (i.hasNext())
1168
            {
1169
              Object n = i.next();
1170
              parent.add(new DynamicUtilTreeNode(n, n));
1171
            }
1172
        }
1173
      else if (children != null && children.getClass().isArray())
1174
        {
1175
          Object[] arr = (Object[]) children;
1176
          for (int i = 0; i < arr.length; ++i)
1177
            parent.add(new DynamicUtilTreeNode(arr[i], arr[i]));
1178
        }
1179
    }
1180
  }
1181
 
1182
  /**
1183
   * Listens to the model of the JTree and updates the property
1184
   * <code>expandedState</code> if nodes are removed or changed.
1185
   */
1186
  protected class TreeModelHandler implements TreeModelListener
1187
  {
1188
 
1189
    /**
1190
     * Creates a new instance of TreeModelHandler.
1191
     */
1192
    protected TreeModelHandler()
1193
    {
1194
      // Nothing to do here.
1195
    }
1196
 
1197
    /**
1198
     * Notifies when a node has changed in some ways. This does not include
1199
     * that a node has changed its location or changed it's children. It
1200
     * only means that some attributes of the node have changed that might
1201
     * affect its presentation.
1202
     *
1203
     * This method is called after the actual change occured.
1204
     *
1205
     * @param ev the TreeModelEvent describing the change
1206
     */
1207
    public void treeNodesChanged(TreeModelEvent ev)
1208
    {
1209
      // Nothing to do here.
1210
    }
1211
 
1212
    /**
1213
     * Notifies when a node is inserted into the tree.
1214
     *
1215
     * This method is called after the actual change occured.
1216
     *
1217
     * @param ev the TreeModelEvent describing the change
1218
     */
1219
    public void treeNodesInserted(TreeModelEvent ev)
1220
    {
1221
      // nothing to do here
1222
    }
1223
 
1224
    /**
1225
     * Notifies when a node is removed from the tree.
1226
     *
1227
     * This method is called after the actual change occured.
1228
     *
1229
     * @param ev the TreeModelEvent describing the change
1230
         */
1231
    public void treeNodesRemoved(TreeModelEvent ev)
1232
    {
1233
      if (ev != null)
1234
        {
1235
          TreePath parent = ev.getTreePath();
1236
          Object[] children = ev.getChildren();
1237
          TreeSelectionModel sm = getSelectionModel();
1238
          if (children != null)
1239
            {
1240
              TreePath path;
1241
              Vector toRemove = new Vector();
1242
              // Collect items that we must remove.
1243
              for (int i = children.length - 1; i >= 0; i--)
1244
                {
1245
                  path = parent.pathByAddingChild(children[i]);
1246
                  if (nodeStates.containsKey(path))
1247
                    toRemove.add(path);
1248
                  // Clear selection while we are at it.
1249
                  if (sm != null)
1250
                    removeDescendantSelectedPaths(path, true);
1251
                }
1252
              if (toRemove.size() > 0)
1253
                removeDescendantToggledPaths(toRemove.elements());
1254
              TreeModel model = getModel();
1255
              if (model == null || model.isLeaf(parent.getLastPathComponent()))
1256
                nodeStates.remove(parent);
1257
            }
1258
        }
1259
    }
1260
 
1261
    /**
1262
     * Notifies when the structure of the tree is changed.
1263
     *
1264
     * This method is called after the actual change occured.
1265
     *
1266
     * @param ev the TreeModelEvent describing the change
1267
     */
1268
    public void treeStructureChanged(TreeModelEvent ev)
1269
    {
1270
      if (ev != null)
1271
        {
1272
          TreePath parent = ev.getTreePath();
1273
          if (parent != null)
1274
            {
1275
              if (parent.getPathCount() == 1)
1276
                {
1277
                  // We have a new root, clear everything.
1278
                  clearToggledPaths();
1279
                  Object root = treeModel.getRoot();
1280
                  if (root != null && treeModel.isLeaf(root))
1281
                    nodeStates.put(parent, Boolean.TRUE);
1282
                }
1283
              else if (nodeStates.containsKey(parent))
1284
                {
1285
                  Vector toRemove = new Vector();
1286
                  boolean expanded = isExpanded(parent);
1287
                  toRemove.add(parent);
1288
                  removeDescendantToggledPaths(toRemove.elements());
1289
                  if (expanded)
1290
                    {
1291
                      TreeModel model = getModel();
1292
                      if (model != null
1293
                          || model.isLeaf(parent.getLastPathComponent()))
1294
                        collapsePath(parent);
1295
                      else
1296
                        nodeStates.put(parent, Boolean.TRUE);
1297
                    }
1298
                }
1299
              removeDescendantSelectedPaths(parent, false);
1300
            }
1301
        }
1302
    }
1303
  }
1304
 
1305
  /**
1306
   * This redirects TreeSelectionEvents and rewrites the source of it to be
1307
   * this JTree. This is typically done when the tree model generates an
1308
   * event, but the JTree object associated with that model should be listed
1309
   * as the actual source of the event.
1310
   */
1311
  protected class TreeSelectionRedirector implements TreeSelectionListener,
1312
                                                     Serializable
1313
  {
1314
    /** The serial version UID. */
1315
    private static final long serialVersionUID = -3505069663646241664L;
1316
 
1317
    /**
1318
     * Creates a new instance of TreeSelectionRedirector
1319
     */
1320
    protected TreeSelectionRedirector()
1321
    {
1322
      // Nothing to do here.
1323
    }
1324
 
1325
    /**
1326
     * Notifies when the tree selection changes.
1327
     *
1328
     * @param ev the TreeSelectionEvent that describes the change
1329
     */
1330
    public void valueChanged(TreeSelectionEvent ev)
1331
    {
1332
      TreeSelectionEvent rewritten =
1333
        (TreeSelectionEvent) ev.cloneWithSource(JTree.this);
1334
      fireValueChanged(rewritten);
1335
    }
1336
  }
1337
 
1338
  /**
1339
   * A TreeModel that does not allow anything to be selected.
1340
   */
1341
  protected static class EmptySelectionModel extends DefaultTreeSelectionModel
1342
  {
1343
    /** The serial version UID. */
1344
    private static final long serialVersionUID = -5815023306225701477L;
1345
 
1346
    /**
1347
     * The shared instance of this model.
1348
     */
1349
    protected static final EmptySelectionModel sharedInstance =
1350
      new EmptySelectionModel();
1351
 
1352
    /**
1353
     * Creates a new instance of EmptySelectionModel.
1354
     */
1355
    protected EmptySelectionModel()
1356
    {
1357
      // Nothing to do here.
1358
    }
1359
 
1360
    /**
1361
     * Returns the shared instance of EmptySelectionModel.
1362
     *
1363
     * @return the shared instance of EmptySelectionModel
1364
     */
1365
    public static EmptySelectionModel sharedInstance()
1366
    {
1367
      return sharedInstance;
1368
    }
1369
 
1370
    /**
1371
     * This catches attempts to set a selection and sets nothing instead.
1372
     *
1373
     * @param paths not used here
1374
     */
1375
    public void setSelectionPaths(TreePath[] paths)
1376
    {
1377
      // We don't allow selections in this class.
1378
    }
1379
 
1380
    /**
1381
     * This catches attempts to add something to the selection.
1382
     *
1383
     * @param paths not used here
1384
     */
1385
    public void addSelectionPaths(TreePath[] paths)
1386
    {
1387
      // We don't allow selections in this class.
1388
    }
1389
 
1390
    /**
1391
     * This catches attempts to remove something from the selection.
1392
     *
1393
     * @param paths not used here
1394
     */
1395
    public void removeSelectionPaths(TreePath[] paths)
1396
    {
1397
      // We don't allow selections in this class.
1398
    }
1399
  }
1400
 
1401
  private static final long serialVersionUID = 7559816092864483649L;
1402
 
1403
  public static final String CELL_EDITOR_PROPERTY = "cellEditor";
1404
 
1405
  public static final String CELL_RENDERER_PROPERTY = "cellRenderer";
1406
 
1407
  public static final String EDITABLE_PROPERTY = "editable";
1408
 
1409
  public static final String INVOKES_STOP_CELL_EDITING_PROPERTY =
1410
    "invokesStopCellEditing";
1411
 
1412
  public static final String LARGE_MODEL_PROPERTY = "largeModel";
1413
 
1414
  public static final String ROOT_VISIBLE_PROPERTY = "rootVisible";
1415
 
1416
  public static final String ROW_HEIGHT_PROPERTY = "rowHeight";
1417
 
1418
  public static final String SCROLLS_ON_EXPAND_PROPERTY = "scrollsOnExpand";
1419
 
1420
  public static final String SELECTION_MODEL_PROPERTY = "selectionModel";
1421
 
1422
  public static final String SHOWS_ROOT_HANDLES_PROPERTY = "showsRootHandles";
1423
 
1424
  public static final String TOGGLE_CLICK_COUNT_PROPERTY = "toggleClickCount";
1425
 
1426
  public static final String TREE_MODEL_PROPERTY = "model";
1427
 
1428
  public static final String VISIBLE_ROW_COUNT_PROPERTY = "visibleRowCount";
1429
 
1430
  /** @since 1.3 */
1431
  public static final String ANCHOR_SELECTION_PATH_PROPERTY =
1432
    "anchorSelectionPath";
1433
 
1434
        /** @since 1.3 */
1435
  public static final String LEAD_SELECTION_PATH_PROPERTY = "leadSelectionPath";
1436
 
1437
  /** @since 1.3 */
1438
  public static final String EXPANDS_SELECTED_PATHS_PROPERTY =
1439
    "expandsSelectedPaths";
1440
 
1441
  private static final Object EXPANDED = Boolean.TRUE;
1442
 
1443
  private static final Object COLLAPSED = Boolean.FALSE;
1444
 
1445
  private boolean dragEnabled;
1446
 
1447
  private boolean expandsSelectedPaths;
1448
 
1449
  private TreePath anchorSelectionPath;
1450
 
1451
  /**
1452
   * This contains the state of all nodes in the tree. Al/ entries map the
1453
   * TreePath of a note to to its state. Valid states are EXPANDED and
1454
   * COLLAPSED. Nodes not in this Hashtable are assumed state COLLAPSED.
1455
   *
1456
   * This is package private to avoid accessor methods.
1457
   */
1458
  Hashtable nodeStates = new Hashtable();
1459
 
1460
  protected transient TreeCellEditor cellEditor;
1461
 
1462
  protected transient TreeCellRenderer cellRenderer;
1463
 
1464
  protected boolean editable;
1465
 
1466
  protected boolean invokesStopCellEditing;
1467
 
1468
  protected boolean largeModel;
1469
 
1470
  protected boolean rootVisible;
1471
 
1472
  protected int rowHeight;
1473
 
1474
  protected boolean scrollsOnExpand;
1475
 
1476
  protected transient TreeSelectionModel selectionModel;
1477
 
1478
  protected boolean showsRootHandles;
1479
 
1480
  protected int toggleClickCount;
1481
 
1482
  protected transient TreeModel treeModel;
1483
 
1484
  protected int visibleRowCount;
1485
 
1486
  /**
1487
   * Handles TreeModelEvents to update the expandedState.
1488
   */
1489
  protected transient TreeModelListener treeModelListener;
1490
 
1491
  /**
1492
   * Redirects TreeSelectionEvents so that the source is this JTree.
1493
   */
1494
  protected TreeSelectionRedirector selectionRedirector =
1495
    new TreeSelectionRedirector();
1496
 
1497
  /**
1498
   * Indicates if the rowHeight property has been set by a client
1499
   * program or by the UI.
1500
   *
1501
   * @see #setUIProperty(String, Object)
1502
   * @see LookAndFeel#installProperty(JComponent, String, Object)
1503
   */
1504
  private boolean clientRowHeightSet = false;
1505
 
1506
  /**
1507
   * Indicates if the scrollsOnExpand property has been set by a client
1508
   * program or by the UI.
1509
   *
1510
   * @see #setUIProperty(String, Object)
1511
   * @see LookAndFeel#installProperty(JComponent, String, Object)
1512
   */
1513
  private boolean clientScrollsOnExpandSet = false;
1514
 
1515
  /**
1516
   * Indicates if the showsRootHandles property has been set by a client
1517
   * program or by the UI.
1518
   *
1519
   * @see #setUIProperty(String, Object)
1520
   * @see LookAndFeel#installProperty(JComponent, String, Object)
1521
   */
1522
  private boolean clientShowsRootHandlesSet = false;
1523
 
1524
  /**
1525
   * Creates a new <code>JTree</code> object.
1526
   */
1527
  public JTree()
1528
  {
1529
    this(getDefaultTreeModel());
1530
  }
1531
 
1532
  /**
1533
   * Creates a new <code>JTree</code> object.
1534
   *
1535
   * @param value the initial nodes in the tree
1536
   */
1537
  public JTree(Hashtable<?, ?> value)
1538
  {
1539
    this(createTreeModel(value));
1540
  }
1541
 
1542
  /**
1543
   * Creates a new <code>JTree</code> object.
1544
   *
1545
   * @param value the initial nodes in the tree
1546
   */
1547
  public JTree(Object[] value)
1548
  {
1549
    this(createTreeModel(value));
1550
  }
1551
 
1552
  /**
1553
   * Creates a new <code>JTree</code> object.
1554
   *
1555
   * @param model the model to use
1556
   */
1557
  public JTree(TreeModel model)
1558
  {
1559
    setRootVisible(true);
1560
    setSelectionModel( new DefaultTreeSelectionModel() );
1561
 
1562
    // The root node appears expanded by default.
1563
    nodeStates = new Hashtable();
1564
 
1565
    // The cell renderer gets set by the UI.
1566
    cellRenderer = null;
1567
 
1568
    // Install the UI before installing the model. This way we avoid double
1569
    // initialization of lots of UI and model stuff inside the UI and related
1570
    // classes. The necessary UI updates are performed via property change
1571
    // events to the UI.
1572
    updateUI();
1573
    setModel(model);
1574
  }
1575
 
1576
  /**
1577
   * Creates a new <code>JTree</code> object.
1578
   *
1579
   * @param root the root node
1580
   */
1581
  public JTree(TreeNode root)
1582
  {
1583
    this(root, false);
1584
  }
1585
 
1586
  /**
1587
   * Creates a new <code>JTree</code> object.
1588
   *
1589
   * @param root the root node
1590
   * @param asksAllowChildren if false, all nodes without children are leaf
1591
   *        nodes. If true, only nodes that do not allow children are leaf
1592
   *        nodes.
1593
   */
1594
  public JTree(TreeNode root, boolean asksAllowChildren)
1595
  {
1596
    this(new DefaultTreeModel(root, asksAllowChildren));
1597
  }
1598
 
1599
  /**
1600
   * Creates a new <code>JTree</code> object.
1601
   *
1602
   * @param value the initial nodes in the tree
1603
   */
1604
  public JTree(Vector<?> value)
1605
  {
1606
    this(createTreeModel(value));
1607
  }
1608
 
1609
  public int getRowForPath(TreePath path)
1610
  {
1611
    TreeUI ui = getUI();
1612
 
1613
    if (ui != null)
1614
      return ui.getRowForPath(this, path);
1615
 
1616
    return -1;
1617
  }
1618
 
1619
  public TreePath getPathForRow(int row)
1620
  {
1621
    TreeUI ui = getUI();
1622
    return ui != null ? ui.getPathForRow(this, row) : null;
1623
  }
1624
 
1625
  /**
1626
   * Get the pathes that are displayes between the two given rows.
1627
   *
1628
   * @param index0 the starting row, inclusive
1629
   * @param index1 the ending row, inclusive
1630
   *
1631
   * @return the array of the tree pathes
1632
   */
1633
  protected TreePath[] getPathBetweenRows(int index0, int index1)
1634
  {
1635
    TreeUI ui = getUI();
1636
 
1637
    if (ui == null)
1638
      return null;
1639
 
1640
    int minIndex = Math.min(index0, index1);
1641
    int maxIndex = Math.max(index0, index1);
1642
    TreePath[] paths = new TreePath[maxIndex - minIndex + 1];
1643
 
1644
    for (int i = minIndex; i <= maxIndex; ++i)
1645
      paths[i - minIndex] = ui.getPathForRow(this, i);
1646
 
1647
    return paths;
1648
  }
1649
 
1650
  /**
1651
   * Creates a new <code>TreeModel</code> object.
1652
   *
1653
   * @param value the values stored in the model
1654
   */
1655
  protected static TreeModel createTreeModel(Object value)
1656
  {
1657
    return new DefaultTreeModel(new DynamicUtilTreeNode(value, value));
1658
  }
1659
 
1660
  /**
1661
   * Return the UI associated with this <code>JTree</code> object.
1662
   *
1663
   * @return the associated <code>TreeUI</code> object
1664
   */
1665
  public TreeUI getUI()
1666
  {
1667
    return (TreeUI) ui;
1668
  }
1669
 
1670
  /**
1671
   * Sets the UI associated with this <code>JTree</code> object.
1672
   *
1673
   * @param ui the <code>TreeUI</code> to associate
1674
   */
1675
  public void setUI(TreeUI ui)
1676
  {
1677
    super.setUI(ui);
1678
  }
1679
 
1680
  /**
1681
   * This method resets the UI used to the Look and Feel defaults..
1682
   */
1683
  public void updateUI()
1684
  {
1685
    setUI((TreeUI) UIManager.getUI(this));
1686
  }
1687
 
1688
  /**
1689
   * This method returns the String ID of the UI class of Separator.
1690
   *
1691
   * @return The UI class' String ID.
1692
   */
1693
  public String getUIClassID()
1694
  {
1695
    return "TreeUI";
1696
  }
1697
 
1698
  /**
1699
   * Gets the AccessibleContext associated with this
1700
   * <code>JTree</code>.
1701
   *
1702
   * @return the associated context
1703
   */
1704
  public AccessibleContext getAccessibleContext()
1705
  {
1706
    return new AccessibleJTree();
1707
  }
1708
 
1709
  /**
1710
   * Returns the preferred viewport size.
1711
   *
1712
   * @return the preferred size
1713
   */
1714
  public Dimension getPreferredScrollableViewportSize()
1715
  {
1716
    return getPreferredSize();
1717
  }
1718
 
1719
  /**
1720
   * Return the preferred scrolling amount (in pixels) for the given scrolling
1721
   * direction and orientation. This method handles a partially exposed row by
1722
   * returning the distance required to completely expose the item.
1723
   *
1724
   * @param visibleRect the currently visible part of the component.
1725
   * @param orientation the scrolling orientation
1726
   * @param direction the scrolling direction (negative - up, positive -down).
1727
   *          The values greater than one means that more mouse wheel or similar
1728
   *          events were generated, and hence it is better to scroll the longer
1729
   *          distance.
1730
   * @author Audrius Meskauskas (audriusa@bioinformatics.org)
1731
   */
1732
  public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation,
1733
                                        int direction)
1734
  {
1735
    int delta = 0;
1736
 
1737
    // Round so that the top would start from the row boundary
1738
    if (orientation == SwingConstants.VERTICAL)
1739
      {
1740
        int row = getClosestRowForLocation(0, visibleRect.y);
1741
        if (row != -1)
1742
          {
1743
            Rectangle b = getRowBounds(row);
1744
            if (b.y != visibleRect.y)
1745
              {
1746
                if (direction < 0)
1747
                  delta = Math.max(0, visibleRect.y - b.y);
1748
                else
1749
                  delta = b.y + b.height - visibleRect.y;
1750
              }
1751
            else
1752
              {
1753
                if (direction < 0)
1754
                  {
1755
                    if (row != 0)
1756
                      {
1757
                        b = getRowBounds(row - 1);
1758
                        delta = b.height;
1759
                      }
1760
                  }
1761
                else
1762
                  delta = b.height;
1763
              }
1764
          }
1765
      }
1766
    else
1767
      // The RI always  returns 4 for HORIZONTAL scrolling.
1768
      delta = 4;
1769
    return delta;
1770
  }
1771
 
1772
  public int getScrollableBlockIncrement(Rectangle visibleRect,
1773
                                         int orientation, int direction)
1774
  {
1775
    int block;
1776
    if (orientation == SwingConstants.VERTICAL)
1777
      block = visibleRect.height;
1778
    else
1779
      block = visibleRect.width;
1780
    return block;
1781
  }
1782
 
1783
  public boolean getScrollableTracksViewportHeight()
1784
  {
1785
    if (getParent() instanceof JViewport)
1786
      return ((JViewport) getParent()).getHeight() > getPreferredSize().height;
1787
    return false;
1788
  }
1789
 
1790
  public boolean getScrollableTracksViewportWidth()
1791
  {
1792
    if (getParent() instanceof JViewport)
1793
      return ((JViewport) getParent()).getWidth() > getPreferredSize().width;
1794
    return false;
1795
  }
1796
 
1797
  /**
1798
   * Adds a <code>TreeExpansionListener</code> object to the tree.
1799
   *
1800
   * @param listener the listener to add
1801
   */
1802
  public void addTreeExpansionListener(TreeExpansionListener listener)
1803
  {
1804
    listenerList.add(TreeExpansionListener.class, listener);
1805
  }
1806
 
1807
  /**
1808
   * Removes a <code>TreeExpansionListener</code> object from the tree.
1809
   *
1810
   * @param listener the listener to remove
1811
   */
1812
  public void removeTreeExpansionListener(TreeExpansionListener listener)
1813
  {
1814
    listenerList.remove(TreeExpansionListener.class, listener);
1815
  }
1816
 
1817
  /**
1818
   * Returns all added <code>TreeExpansionListener</code> objects.
1819
   *
1820
   * @return an array of listeners
1821
   */
1822
  public TreeExpansionListener[] getTreeExpansionListeners()
1823
  {
1824
    return (TreeExpansionListener[]) getListeners(TreeExpansionListener.class);
1825
  }
1826
 
1827
  /**
1828
   * Notifies all listeners that the tree was collapsed.
1829
   *
1830
   * @param path the path to the node that was collapsed
1831
   */
1832
  public void fireTreeCollapsed(TreePath path)
1833
  {
1834
    TreeExpansionEvent event = new TreeExpansionEvent(this, path);
1835
    TreeExpansionListener[] listeners = getTreeExpansionListeners();
1836
 
1837
    for (int index = 0; index < listeners.length; ++index)
1838
      listeners[index].treeCollapsed(event);
1839
  }
1840
 
1841
  /**
1842
   * Notifies all listeners that the tree was expanded.
1843
   *
1844
   * @param path the path to the node that was expanded
1845
   */
1846
  public void fireTreeExpanded(TreePath path)
1847
  {
1848
    TreeExpansionEvent event = new TreeExpansionEvent(this, path);
1849
    TreeExpansionListener[] listeners = getTreeExpansionListeners();
1850
 
1851
    for (int index = 0; index < listeners.length; ++index)
1852
      listeners[index].treeExpanded(event);
1853
  }
1854
 
1855
  /**
1856
   * Adds a <code>TreeSelctionListener</code> object to the tree.
1857
   *
1858
   * @param listener the listener to add
1859
   */
1860
  public void addTreeSelectionListener(TreeSelectionListener listener)
1861
  {
1862
    listenerList.add(TreeSelectionListener.class, listener);
1863
  }
1864
 
1865
  /**
1866
   * Removes a <code>TreeSelectionListener</code> object from the tree.
1867
   *
1868
   * @param listener the listener to remove
1869
   */
1870
  public void removeTreeSelectionListener(TreeSelectionListener listener)
1871
  {
1872
    listenerList.remove(TreeSelectionListener.class, listener);
1873
  }
1874
 
1875
  /**
1876
   * Returns all added <code>TreeSelectionListener</code> objects.
1877
   *
1878
   * @return an array of listeners
1879
   */
1880
  public TreeSelectionListener[] getTreeSelectionListeners()
1881
  {
1882
    return (TreeSelectionListener[])
1883
    getListeners(TreeSelectionListener.class);
1884
  }
1885
 
1886
  /**
1887
   * Notifies all listeners when the selection of the tree changed.
1888
   *
1889
   * @param event the event to send
1890
   */
1891
  protected void fireValueChanged(TreeSelectionEvent event)
1892
  {
1893
    TreeSelectionListener[] listeners = getTreeSelectionListeners();
1894
 
1895
    for (int index = 0; index < listeners.length; ++index)
1896
      listeners[index].valueChanged(event);
1897
  }
1898
 
1899
  /**
1900
   * Adds a <code>TreeWillExpandListener</code> object to the tree.
1901
   *
1902
   * @param listener the listener to add
1903
   */
1904
  public void addTreeWillExpandListener(TreeWillExpandListener listener)
1905
  {
1906
    listenerList.add(TreeWillExpandListener.class, listener);
1907
  }
1908
 
1909
  /**
1910
   * Removes a <code>TreeWillExpandListener</code> object from the tree.
1911
   *
1912
   * @param listener the listener to remove
1913
   */
1914
  public void removeTreeWillExpandListener(TreeWillExpandListener listener)
1915
  {
1916
    listenerList.remove(TreeWillExpandListener.class, listener);
1917
  }
1918
 
1919
  /**
1920
   * Returns all added <code>TreeWillExpandListener</code> objects.
1921
   *
1922
   * @return an array of listeners
1923
   */
1924
  public TreeWillExpandListener[] getTreeWillExpandListeners()
1925
  {
1926
    return (TreeWillExpandListener[])
1927
    getListeners(TreeWillExpandListener.class);
1928
  }
1929
 
1930
  /**
1931
   * Notifies all listeners that the tree will collapse.
1932
   *
1933
   * @param path the path to the node that will collapse
1934
   */
1935
  public void fireTreeWillCollapse(TreePath path) throws ExpandVetoException
1936
  {
1937
    TreeExpansionEvent event = new TreeExpansionEvent(this, path);
1938
    TreeWillExpandListener[] listeners = getTreeWillExpandListeners();
1939
 
1940
    for (int index = 0; index < listeners.length; ++index)
1941
      listeners[index].treeWillCollapse(event);
1942
  }
1943
 
1944
  /**
1945
   * Notifies all listeners that the tree will expand.
1946
   *
1947
   * @param path the path to the node that will expand
1948
   */
1949
  public void fireTreeWillExpand(TreePath path) throws ExpandVetoException
1950
  {
1951
    TreeExpansionEvent event = new TreeExpansionEvent(this, path);
1952
    TreeWillExpandListener[] listeners = getTreeWillExpandListeners();
1953
 
1954
    for (int index = 0; index < listeners.length; ++index)
1955
      listeners[index].treeWillExpand(event);
1956
  }
1957
 
1958
  /**
1959
   * Returns the model of this <code>JTree</code> object.
1960
   *
1961
   * @return the associated <code>TreeModel</code>
1962
   */
1963
  public TreeModel getModel()
1964
  {
1965
    return treeModel;
1966
  }
1967
 
1968
  /**
1969
   * Sets the model to use in <code>JTree</code>.
1970
   *
1971
   * @param model the <code>TreeModel</code> to use
1972
   */
1973
  public void setModel(TreeModel model)
1974
  {
1975
    if (treeModel == model)
1976
      return;
1977
 
1978
    // Remove listeners from old model.
1979
    if (treeModel != null && treeModelListener != null)
1980
      treeModel.removeTreeModelListener(treeModelListener);
1981
 
1982
    // add treeModelListener to the new model
1983
    if (treeModelListener == null)
1984
      treeModelListener = createTreeModelListener();
1985
    if (model != null) // as setModel(null) is allowed
1986
      model.addTreeModelListener(treeModelListener);
1987
 
1988
    TreeModel oldValue = treeModel;
1989
    treeModel = model;
1990
    clearToggledPaths();
1991
 
1992
    if (treeModel != null)
1993
      {
1994
        if (treeModelListener == null)
1995
          treeModelListener = createTreeModelListener();
1996
        if (treeModelListener != null)
1997
          treeModel.addTreeModelListener(treeModelListener);
1998
        Object root = treeModel.getRoot();
1999
        if (root != null && !treeModel.isLeaf(root))
2000
          {
2001
            nodeStates.put(new TreePath(root), Boolean.TRUE);
2002
          }
2003
      }
2004
 
2005
    firePropertyChange(TREE_MODEL_PROPERTY, oldValue, model);
2006
  }
2007
 
2008
  /**
2009
   * Checks if this <code>JTree</code> object is editable.
2010
   *
2011
   * @return <code>true</code> if this tree object is editable,
2012
   *         <code>false</code> otherwise
2013
   */
2014
  public boolean isEditable()
2015
  {
2016
    return editable;
2017
  }
2018
 
2019
  /**
2020
   * Sets the <code>editable</code> property.
2021
   *
2022
   * @param flag <code>true</code> to make this tree object editable,
2023
   *        <code>false</code> otherwise
2024
   */
2025
  public void setEditable(boolean flag)
2026
  {
2027
    if (editable == flag)
2028
      return;
2029
 
2030
    boolean oldValue = editable;
2031
    editable = flag;
2032
    firePropertyChange(EDITABLE_PROPERTY, oldValue, editable);
2033
  }
2034
 
2035
  /**
2036
   * Checks if the root element is visible.
2037
   *
2038
   * @return <code>true</code> if the root element is visible,
2039
   *         <code>false</code> otherwise
2040
   */
2041
  public boolean isRootVisible()
2042
  {
2043
    return rootVisible;
2044
  }
2045
 
2046
  public void setRootVisible(boolean flag)
2047
  {
2048
    if (rootVisible == flag)
2049
      return;
2050
 
2051
    // If the root is currently selected, unselect it
2052
    if (rootVisible && !flag)
2053
      {
2054
        TreeSelectionModel model = getSelectionModel();
2055
        // The root is always shown in the first row
2056
        TreePath rootPath = getPathForRow(0);
2057
        model.removeSelectionPath(rootPath);
2058
      }
2059
 
2060
    boolean oldValue = rootVisible;
2061
    rootVisible = flag;
2062
    firePropertyChange(ROOT_VISIBLE_PROPERTY, oldValue, flag);
2063
 
2064
  }
2065
 
2066
  public boolean getShowsRootHandles()
2067
  {
2068
    return showsRootHandles;
2069
  }
2070
 
2071
  public void setShowsRootHandles(boolean flag)
2072
  {
2073
    clientShowsRootHandlesSet = true;
2074
 
2075
    if (showsRootHandles == flag)
2076
      return;
2077
 
2078
    boolean oldValue = showsRootHandles;
2079
    showsRootHandles = flag;
2080
    firePropertyChange(SHOWS_ROOT_HANDLES_PROPERTY, oldValue, flag);
2081
  }
2082
 
2083
  public TreeCellEditor getCellEditor()
2084
  {
2085
    return cellEditor;
2086
  }
2087
 
2088
  public void setCellEditor(TreeCellEditor editor)
2089
  {
2090
    if (cellEditor == editor)
2091
      return;
2092
 
2093
    TreeCellEditor oldValue = cellEditor;
2094
    cellEditor = editor;
2095
    firePropertyChange(CELL_EDITOR_PROPERTY, oldValue, editor);
2096
  }
2097
 
2098
  public TreeCellRenderer getCellRenderer()
2099
  {
2100
    return cellRenderer;
2101
  }
2102
 
2103
  public void setCellRenderer(TreeCellRenderer newRenderer)
2104
  {
2105
    if (cellRenderer == newRenderer)
2106
      return;
2107
 
2108
    TreeCellRenderer oldValue = cellRenderer;
2109
    cellRenderer = newRenderer;
2110
    firePropertyChange(CELL_RENDERER_PROPERTY, oldValue, newRenderer);
2111
  }
2112
 
2113
  public TreeSelectionModel getSelectionModel()
2114
  {
2115
    return selectionModel;
2116
  }
2117
 
2118
  public void setSelectionModel(TreeSelectionModel model)
2119
  {
2120
    if (selectionModel == model)
2121
      return;
2122
 
2123
    if( model == null )
2124
      model = EmptySelectionModel.sharedInstance();
2125
 
2126
    if (selectionModel != null)
2127
      selectionModel.removeTreeSelectionListener(selectionRedirector);
2128
 
2129
    TreeSelectionModel oldValue = selectionModel;
2130
    selectionModel = model;
2131
 
2132
    selectionModel.addTreeSelectionListener(selectionRedirector);
2133
 
2134
    firePropertyChange(SELECTION_MODEL_PROPERTY, oldValue, model);
2135
    revalidate();
2136
    repaint();
2137
  }
2138
 
2139
  public int getVisibleRowCount()
2140
  {
2141
    return visibleRowCount;
2142
  }
2143
 
2144
  public void setVisibleRowCount(int rows)
2145
  {
2146
    if (visibleRowCount == rows)
2147
      return;
2148
 
2149
    int oldValue = visibleRowCount;
2150
    visibleRowCount = rows;
2151
    firePropertyChange(VISIBLE_ROW_COUNT_PROPERTY, oldValue, rows);
2152
  }
2153
 
2154
  public boolean isLargeModel()
2155
  {
2156
    return largeModel;
2157
  }
2158
 
2159
  public void setLargeModel(boolean large)
2160
  {
2161
    if (largeModel == large)
2162
      return;
2163
 
2164
    boolean oldValue = largeModel;
2165
    largeModel = large;
2166
    firePropertyChange(LARGE_MODEL_PROPERTY, oldValue, large);
2167
  }
2168
 
2169
  public int getRowHeight()
2170
  {
2171
    return rowHeight;
2172
  }
2173
 
2174
  public void setRowHeight(int height)
2175
  {
2176
    clientRowHeightSet = true;
2177
 
2178
    if (rowHeight == height)
2179
      return;
2180
 
2181
    int oldValue = rowHeight;
2182
    rowHeight = height;
2183
    firePropertyChange(ROW_HEIGHT_PROPERTY, oldValue, height);
2184
  }
2185
 
2186
  public boolean isFixedRowHeight()
2187
  {
2188
    return rowHeight > 0;
2189
  }
2190
 
2191
  public boolean getInvokesStopCellEditing()
2192
  {
2193
    return invokesStopCellEditing;
2194
  }
2195
 
2196
  public void setInvokesStopCellEditing(boolean invoke)
2197
  {
2198
    if (invokesStopCellEditing == invoke)
2199
      return;
2200
 
2201
    boolean oldValue = invokesStopCellEditing;
2202
    invokesStopCellEditing = invoke;
2203
    firePropertyChange(INVOKES_STOP_CELL_EDITING_PROPERTY,
2204
                       oldValue, invoke);
2205
  }
2206
 
2207
  /**
2208
   * @since 1.3
2209
   */
2210
  public int getToggleClickCount()
2211
  {
2212
    return toggleClickCount;
2213
  }
2214
 
2215
  /**
2216
   * @since 1.3
2217
   */
2218
  public void setToggleClickCount(int count)
2219
  {
2220
    if (toggleClickCount == count)
2221
      return;
2222
 
2223
    int oldValue = toggleClickCount;
2224
    toggleClickCount = count;
2225
    firePropertyChange(TOGGLE_CLICK_COUNT_PROPERTY, oldValue, count);
2226
  }
2227
 
2228
  public void scrollPathToVisible(TreePath path)
2229
  {
2230
    if (path == null)
2231
      return;
2232
    Rectangle rect = getPathBounds(path);
2233
    scrollRectToVisible(rect);
2234
  }
2235
 
2236
  public void scrollRowToVisible(int row)
2237
  {
2238
    scrollPathToVisible(getPathForRow(row));
2239
  }
2240
 
2241
  public boolean getScrollsOnExpand()
2242
  {
2243
    return scrollsOnExpand;
2244
  }
2245
 
2246
  public void setScrollsOnExpand(boolean scroll)
2247
  {
2248
    clientScrollsOnExpandSet = true;
2249
    if (scrollsOnExpand == scroll)
2250
      return;
2251
 
2252
    boolean oldValue = scrollsOnExpand;
2253
    scrollsOnExpand = scroll;
2254
    firePropertyChange(SCROLLS_ON_EXPAND_PROPERTY, oldValue, scroll);
2255
  }
2256
 
2257
  public void setSelectionPath(TreePath path)
2258
  {
2259
    clearSelectionPathStates();
2260
    selectionModel.setSelectionPath(path);
2261
  }
2262
 
2263
  public void setSelectionPaths(TreePath[] paths)
2264
  {
2265
    clearSelectionPathStates();
2266
    selectionModel.setSelectionPaths(paths);
2267
  }
2268
 
2269
  /**
2270
   * This method, and all calls to it, should be removed once the
2271
   * DefaultTreeModel fires events properly.  Maintenance of the nodeStates
2272
   * table should really be done in the TreeModelHandler.
2273
   */
2274
  private void clearSelectionPathStates()
2275
  {
2276
    TreePath[] oldPaths = selectionModel.getSelectionPaths();
2277
    if (oldPaths != null)
2278
      for (int i = 0; i < oldPaths.length; i++)
2279
        nodeStates.remove(oldPaths[i]);
2280
  }
2281
 
2282
  public void setSelectionRow(int row)
2283
  {
2284
    TreePath path = getPathForRow(row);
2285
 
2286
    if (path != null)
2287
      setSelectionPath(path);
2288
  }
2289
 
2290
  public void setSelectionRows(int[] rows)
2291
  {
2292
    // Make sure we have an UI so getPathForRow() does not return null.
2293
    if (rows == null || getUI() == null)
2294
      return;
2295
 
2296
    TreePath[] paths = new TreePath[rows.length];
2297
 
2298
    for (int i = rows.length - 1; i >= 0; --i)
2299
      paths[i] = getPathForRow(rows[i]);
2300
 
2301
    setSelectionPaths(paths);
2302
  }
2303
 
2304
  public void setSelectionInterval(int index0, int index1)
2305
  {
2306
    TreePath[] paths = getPathBetweenRows(index0, index1);
2307
 
2308
    if (paths != null)
2309
      setSelectionPaths(paths);
2310
  }
2311
 
2312
  public void addSelectionPath(TreePath path)
2313
  {
2314
    selectionModel.addSelectionPath(path);
2315
  }
2316
 
2317
  public void addSelectionPaths(TreePath[] paths)
2318
  {
2319
    selectionModel.addSelectionPaths(paths);
2320
  }
2321
 
2322
  public void addSelectionRow(int row)
2323
  {
2324
    TreePath path = getPathForRow(row);
2325
 
2326
    if (path != null)
2327
      selectionModel.addSelectionPath(path);
2328
  }
2329
 
2330
  public void addSelectionRows(int[] rows)
2331
  {
2332
    // Make sure we have an UI so getPathForRow() does not return null.
2333
    if (rows == null || getUI() == null)
2334
      return;
2335
 
2336
    TreePath[] paths = new TreePath[rows.length];
2337
 
2338
    for (int i = rows.length - 1; i >= 0; --i)
2339
      paths[i] = getPathForRow(rows[i]);
2340
 
2341
    addSelectionPaths(paths);
2342
  }
2343
 
2344
  /**
2345
   * Select all rows between the two given indexes, inclusive. The method
2346
   * will not select the inner leaves and braches of the currently collapsed
2347
   * nodes in this interval.
2348
   *
2349
   * @param index0 the starting row, inclusive
2350
   * @param index1 the ending row, inclusive
2351
   */
2352
  public void addSelectionInterval(int index0, int index1)
2353
  {
2354
    TreePath[] paths = getPathBetweenRows(index0, index1);
2355
 
2356
    if (paths != null)
2357
      addSelectionPaths(paths);
2358
  }
2359
 
2360
  public void removeSelectionPath(TreePath path)
2361
  {
2362
    clearSelectionPathStates();
2363
    selectionModel.removeSelectionPath(path);
2364
  }
2365
 
2366
  public void removeSelectionPaths(TreePath[] paths)
2367
  {
2368
    clearSelectionPathStates();
2369
    selectionModel.removeSelectionPaths(paths);
2370
  }
2371
 
2372
  public void removeSelectionRow(int row)
2373
  {
2374
    TreePath path = getPathForRow(row);
2375
 
2376
    if (path != null)
2377
      removeSelectionPath(path);
2378
  }
2379
 
2380
  public void removeSelectionRows(int[] rows)
2381
  {
2382
    if (rows == null || getUI() == null)
2383
      return;
2384
 
2385
    TreePath[] paths = new TreePath[rows.length];
2386
 
2387
    for (int i = rows.length - 1; i >= 0; --i)
2388
      paths[i] = getPathForRow(rows[i]);
2389
 
2390
    removeSelectionPaths(paths);
2391
  }
2392
 
2393
  public void removeSelectionInterval(int index0, int index1)
2394
  {
2395
    TreePath[] paths = getPathBetweenRows(index0, index1);
2396
 
2397
    if (paths != null)
2398
      removeSelectionPaths(paths);
2399
  }
2400
 
2401
  public void clearSelection()
2402
  {
2403
    selectionModel.clearSelection();
2404
    setLeadSelectionPath(null);
2405
  }
2406
 
2407
  public TreePath getLeadSelectionPath()
2408
  {
2409
    if (selectionModel == null)
2410
      return null;
2411
    else
2412
      return selectionModel.getLeadSelectionPath();
2413
  }
2414
 
2415
  /**
2416
   * @since 1.3
2417
   */
2418
  public void setLeadSelectionPath(TreePath path)
2419
  {
2420
    if (selectionModel != null)
2421
      {
2422
        TreePath oldValue = selectionModel.getLeadSelectionPath();
2423
        if (path == oldValue || path != null && path.equals(oldValue))
2424
          return;
2425
 
2426
        // Repaint the previous and current rows with the lead selection path.
2427
        if (path != null)
2428
          {
2429
            repaint(getPathBounds(path));
2430
            selectionModel.addSelectionPath(path);
2431
          }
2432
 
2433
        if (oldValue != null)
2434
          repaint(getPathBounds(oldValue));
2435
 
2436
        firePropertyChange(LEAD_SELECTION_PATH_PROPERTY, oldValue, path);
2437
      }
2438
  }
2439
 
2440
  /**
2441
   * @since 1.3
2442
   */
2443
  public TreePath getAnchorSelectionPath()
2444
  {
2445
    return anchorSelectionPath;
2446
  }
2447
 
2448
  /**
2449
   * @since 1.3
2450
   */
2451
  public void setAnchorSelectionPath(TreePath path)
2452
  {
2453
    if (anchorSelectionPath == path)
2454
      return;
2455
 
2456
    TreePath oldValue = anchorSelectionPath;
2457
    anchorSelectionPath = path;
2458
    firePropertyChange(ANCHOR_SELECTION_PATH_PROPERTY, oldValue, path);
2459
  }
2460
 
2461
  public int getLeadSelectionRow()
2462
  {
2463
    return selectionModel.getLeadSelectionRow();
2464
  }
2465
 
2466
  public int getMaxSelectionRow()
2467
  {
2468
    return selectionModel.getMaxSelectionRow();
2469
  }
2470
 
2471
  public int getMinSelectionRow()
2472
  {
2473
    return selectionModel.getMinSelectionRow();
2474
  }
2475
 
2476
  public int getSelectionCount()
2477
  {
2478
    return selectionModel.getSelectionCount();
2479
  }
2480
 
2481
  public TreePath getSelectionPath()
2482
  {
2483
    return selectionModel.getSelectionPath();
2484
  }
2485
 
2486
  public TreePath[] getSelectionPaths()
2487
  {
2488
    return selectionModel.getSelectionPaths();
2489
  }
2490
 
2491
  public int[] getSelectionRows()
2492
  {
2493
    return selectionModel.getSelectionRows();
2494
  }
2495
 
2496
  public boolean isPathSelected(TreePath path)
2497
  {
2498
    return selectionModel.isPathSelected(path);
2499
  }
2500
 
2501
  /**
2502
   * Returns <code>true</code> when the specified row is selected,
2503
   * <code>false</code> otherwise. This call is delegated to the
2504
   * {@link TreeSelectionModel#isRowSelected(int)} method.
2505
   *
2506
   * @param row the row to check
2507
   *
2508
   * @return <code>true</code> when the specified row is selected,
2509
   *         <code>false</code> otherwise
2510
   */
2511
  public boolean isRowSelected(int row)
2512
  {
2513
    return selectionModel.isRowSelected(row);
2514
  }
2515
 
2516
  public boolean isSelectionEmpty()
2517
  {
2518
    return selectionModel.isSelectionEmpty();
2519
  }
2520
 
2521
  /**
2522
   * Return the value of the <code>dragEnabled</code> property.
2523
   *
2524
   * @return the value
2525
   *
2526
   * @since 1.4
2527
   */
2528
  public boolean getDragEnabled()
2529
  {
2530
    return dragEnabled;
2531
  }
2532
 
2533
  /**
2534
   * Set the <code>dragEnabled</code> property.
2535
   *
2536
   * @param enabled new value
2537
   *
2538
   * @since 1.4
2539
   */
2540
  public void setDragEnabled(boolean enabled)
2541
  {
2542
    dragEnabled = enabled;
2543
  }
2544
 
2545
  public int getRowCount()
2546
  {
2547
    TreeUI ui = getUI();
2548
 
2549
    if (ui != null)
2550
      return ui.getRowCount(this);
2551
 
2552
    return 0;
2553
  }
2554
 
2555
  public void collapsePath(TreePath path)
2556
  {
2557
    try
2558
      {
2559
        fireTreeWillCollapse(path);
2560
      }
2561
    catch (ExpandVetoException ev)
2562
      {
2563
        // We do nothing if attempt has been vetoed.
2564
      }
2565
    setExpandedState(path, false);
2566
    fireTreeCollapsed(path);
2567
  }
2568
 
2569
  public void collapseRow(int row)
2570
  {
2571
    if (row < 0 || row >= getRowCount())
2572
      return;
2573
 
2574
    TreePath path = getPathForRow(row);
2575
 
2576
    if (path != null)
2577
      collapsePath(path);
2578
  }
2579
 
2580
  public void expandPath(TreePath path)
2581
  {
2582
    // Don't expand if path is null
2583
    // or is already expanded.
2584
    if (path == null || isExpanded(path))
2585
      return;
2586
 
2587
    try
2588
      {
2589
        fireTreeWillExpand(path);
2590
      }
2591
    catch (ExpandVetoException ev)
2592
      {
2593
        // We do nothing if attempt has been vetoed.
2594
      }
2595
 
2596
    setExpandedState(path, true);
2597
    fireTreeExpanded(path);
2598
  }
2599
 
2600
  public void expandRow(int row)
2601
  {
2602
    if (row < 0 || row >= getRowCount())
2603
      return;
2604
 
2605
    TreePath path = getPathForRow(row);
2606
 
2607
    if (path != null)
2608
      expandPath(path);
2609
  }
2610
 
2611
  public boolean isCollapsed(TreePath path)
2612
  {
2613
    return !isExpanded(path);
2614
  }
2615
 
2616
  public boolean isCollapsed(int row)
2617
  {
2618
    if (row < 0 || row >= getRowCount())
2619
      return false;
2620
 
2621
    TreePath path = getPathForRow(row);
2622
 
2623
    if (path != null)
2624
      return isCollapsed(path);
2625
 
2626
    return false;
2627
  }
2628
 
2629
  public boolean isExpanded(TreePath path)
2630
  {
2631
    if (path == null)
2632
      return false;
2633
 
2634
    Object state = nodeStates.get(path);
2635
 
2636
    if ((state == null) || (state != EXPANDED))
2637
      return false;
2638
 
2639
    TreePath parent = path.getParentPath();
2640
 
2641
    if (parent != null)
2642
      return isExpanded(parent);
2643
 
2644
    return true;
2645
  }
2646
 
2647
  public boolean isExpanded(int row)
2648
  {
2649
    if (row < 0 || row >= getRowCount())
2650
      return false;
2651
 
2652
    TreePath path = getPathForRow(row);
2653
 
2654
    if (path != null)
2655
      return isExpanded(path);
2656
 
2657
    return false;
2658
  }
2659
 
2660
  /**
2661
   * @since 1.3
2662
   */
2663
  public boolean getExpandsSelectedPaths()
2664
  {
2665
    return expandsSelectedPaths;
2666
  }
2667
 
2668
  /**
2669
   * @since 1.3
2670
   */
2671
  public void setExpandsSelectedPaths(boolean flag)
2672
  {
2673
    if (expandsSelectedPaths == flag)
2674
      return;
2675
 
2676
    boolean oldValue = expandsSelectedPaths;
2677
    expandsSelectedPaths = flag;
2678
    firePropertyChange(EXPANDS_SELECTED_PATHS_PROPERTY, oldValue, flag);
2679
  }
2680
 
2681
  public Rectangle getPathBounds(TreePath path)
2682
  {
2683
    TreeUI ui = getUI();
2684
 
2685
    if (ui == null)
2686
      return null;
2687
 
2688
    return ui.getPathBounds(this, path);
2689
  }
2690
 
2691
  public Rectangle getRowBounds(int row)
2692
  {
2693
    TreePath path = getPathForRow(row);
2694
 
2695
    if (path != null)
2696
      return getPathBounds(path);
2697
 
2698
    return null;
2699
  }
2700
 
2701
  public boolean isEditing()
2702
  {
2703
    TreeUI ui = getUI();
2704
 
2705
    if (ui != null)
2706
      return ui.isEditing(this);
2707
 
2708
    return false;
2709
  }
2710
 
2711
  public boolean stopEditing()
2712
  {
2713
    TreeUI ui = getUI();
2714
 
2715
    if (isEditing())
2716
      if (ui != null)
2717
        return ui.stopEditing(this);
2718
 
2719
    return false;
2720
  }
2721
 
2722
  public void cancelEditing()
2723
  {
2724
    TreeUI ui = getUI();
2725
 
2726
    if (isEditing())
2727
      if (ui != null)
2728
        ui.cancelEditing(this);
2729
  }
2730
 
2731
  public void startEditingAtPath(TreePath path)
2732
  {
2733
    TreeUI ui = getUI();
2734
 
2735
    if (ui != null)
2736
      ui.startEditingAtPath(this, path);
2737
  }
2738
 
2739
  public TreePath getEditingPath()
2740
  {
2741
    TreeUI ui = getUI();
2742
 
2743
    if (ui != null)
2744
      return ui.getEditingPath(this);
2745
 
2746
    return null;
2747
  }
2748
 
2749
  public TreePath getPathForLocation(int x, int y)
2750
  {
2751
    TreePath path = getClosestPathForLocation(x, y);
2752
 
2753
    if (path != null)
2754
      {
2755
        Rectangle rect = getPathBounds(path);
2756
 
2757
        if ((rect != null) && rect.contains(x, y))
2758
          return path;
2759
      }
2760
 
2761
    return null;
2762
  }
2763
 
2764
  public int getRowForLocation(int x, int y)
2765
  {
2766
    TreePath path = getPathForLocation(x, y);
2767
 
2768
    if (path != null)
2769
      return getRowForPath(path);
2770
 
2771
    return -1;
2772
  }
2773
 
2774
  public TreePath getClosestPathForLocation(int x, int y)
2775
  {
2776
    TreeUI ui = getUI();
2777
 
2778
    if (ui != null)
2779
      return ui.getClosestPathForLocation(this, x, y);
2780
 
2781
    return null;
2782
  }
2783
 
2784
  public int getClosestRowForLocation(int x, int y)
2785
  {
2786
    TreePath path = getClosestPathForLocation(x, y);
2787
 
2788
    if (path != null)
2789
      return getRowForPath(path);
2790
 
2791
    return -1;
2792
  }
2793
 
2794
  public Object getLastSelectedPathComponent()
2795
  {
2796
    TreePath path = getSelectionPath();
2797
 
2798
    if (path != null)
2799
      return path.getLastPathComponent();
2800
 
2801
    return null;
2802
  }
2803
 
2804
  private void doExpandParents(TreePath path, boolean state)
2805
  {
2806
    TreePath parent = path.getParentPath();
2807
 
2808
    if (!isExpanded(parent) && parent != null)
2809
      doExpandParents(parent, false);
2810
 
2811
    nodeStates.put(path, state ? EXPANDED : COLLAPSED);
2812
  }
2813
 
2814
  protected void setExpandedState(TreePath path, boolean state)
2815
  {
2816
    if (path == null)
2817
      return;
2818
 
2819
    doExpandParents(path, state);
2820
  }
2821
 
2822
  protected void clearToggledPaths()
2823
  {
2824
    nodeStates.clear();
2825
  }
2826
 
2827
  protected Enumeration<TreePath> getDescendantToggledPaths(TreePath parent)
2828
  {
2829
    if (parent == null)
2830
      return null;
2831
 
2832
    Enumeration nodes = nodeStates.keys();
2833
    Vector result = new Vector();
2834
 
2835
    while (nodes.hasMoreElements())
2836
      {
2837
        TreePath path = (TreePath) nodes.nextElement();
2838
 
2839
        if (path.isDescendant(parent))
2840
          result.addElement(path);
2841
      }
2842
 
2843
    return result.elements();
2844
  }
2845
 
2846
  public boolean hasBeenExpanded(TreePath path)
2847
  {
2848
    if (path == null)
2849
      return false;
2850
 
2851
    return nodeStates.get(path) != null;
2852
  }
2853
 
2854
  public boolean isVisible(TreePath path)
2855
  {
2856
    if (path == null)
2857
      return false;
2858
 
2859
    TreePath parent = path.getParentPath();
2860
 
2861
    if (parent == null)
2862
      return true; // Is root node.
2863
 
2864
    return isExpanded(parent);
2865
  }
2866
 
2867
  public void makeVisible(TreePath path)
2868
  {
2869
    if (path == null)
2870
      return;
2871
 
2872
    expandPath(path.getParentPath());
2873
  }
2874
 
2875
  public boolean isPathEditable(TreePath path)
2876
  {
2877
    return isEditable();
2878
  }
2879
 
2880
  /**
2881
   * Creates and returns an instance of {@link TreeModelHandler}.
2882
   *
2883
   * @return an instance of {@link TreeModelHandler}
2884
   */
2885
  protected TreeModelListener createTreeModelListener()
2886
  {
2887
    return new TreeModelHandler();
2888
  }
2889
 
2890
  /**
2891
   * Returns a sample TreeModel that can be used in a JTree. This can be used
2892
   * in Bean- or GUI-Builders to show something interesting.
2893
   *
2894
   * @return a sample TreeModel that can be used in a JTree
2895
   */
2896
  protected static TreeModel getDefaultTreeModel()
2897
  {
2898
    DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root node");
2899
    DefaultMutableTreeNode child1 = new DefaultMutableTreeNode("Child node 1");
2900
    DefaultMutableTreeNode child11 =
2901
      new DefaultMutableTreeNode("Child node 1.1");
2902
    DefaultMutableTreeNode child12 =
2903
      new DefaultMutableTreeNode("Child node 1.2");
2904
    DefaultMutableTreeNode child13 =
2905
      new DefaultMutableTreeNode("Child node 1.3");
2906
    DefaultMutableTreeNode child2 = new DefaultMutableTreeNode("Child node 2");
2907
    DefaultMutableTreeNode child21 =
2908
      new DefaultMutableTreeNode("Child node 2.1");
2909
    DefaultMutableTreeNode child22 =
2910
      new DefaultMutableTreeNode("Child node 2.2");
2911
    DefaultMutableTreeNode child23 =
2912
      new DefaultMutableTreeNode("Child node 2.3");
2913
    DefaultMutableTreeNode child24 =
2914
      new DefaultMutableTreeNode("Child node 2.4");
2915
 
2916
    DefaultMutableTreeNode child3 = new DefaultMutableTreeNode("Child node 3");
2917
    root.add(child1);
2918
    root.add(child2);
2919
    root.add(child3);
2920
    child1.add(child11);
2921
    child1.add(child12);
2922
    child1.add(child13);
2923
    child2.add(child21);
2924
    child2.add(child22);
2925
    child2.add(child23);
2926
    child2.add(child24);
2927
    return new DefaultTreeModel(root);
2928
  }
2929
 
2930
  /**
2931
   * Converts the specified value to a String. This is used by the renderers
2932
   * of this JTree and its nodes.
2933
   *
2934
   * This implementation simply returns <code>value.toString()</code> and
2935
   * ignores all other parameters. Subclass this method to control the
2936
   * conversion.
2937
   *
2938
   * @param value the value that is converted to a String
2939
   * @param selected indicates if that value is selected or not
2940
   * @param expanded indicates if that value is expanded or not
2941
   * @param leaf indicates if that value is a leaf node or not
2942
   * @param row the row of the node
2943
   * @param hasFocus indicates if that node has focus or not
2944
   */
2945
  public String convertValueToText(Object value, boolean selected,
2946
                                   boolean expanded, boolean leaf, int row, boolean hasFocus)
2947
  {
2948
    return value.toString();
2949
  }
2950
 
2951
  /**
2952
   * A String representation of this JTree. This is intended to be used for
2953
   * debugging. The returned string may be empty but may not be
2954
   * <code>null</code>.
2955
   *
2956
   * @return a String representation of this JTree
2957
   */
2958
  protected String paramString()
2959
  {
2960
    // TODO: this is completely legal, but it would possibly be nice
2961
    // to return some more content, like the tree structure, some properties
2962
    // etc ...
2963
    return "";
2964
  }
2965
 
2966
  /**
2967
   * Returns all TreePath objects which are a descendants of the given path
2968
   * and are exapanded at the moment of the execution of this method. If the
2969
   * state of any node is beeing toggled while this method is executing this
2970
   * change may be left unaccounted.
2971
   *
2972
   * @param path The parent of this request
2973
   *
2974
   * @return An Enumeration containing TreePath objects
2975
   */
2976
  public Enumeration<TreePath> getExpandedDescendants(TreePath path)
2977
  {
2978
    Enumeration paths = nodeStates.keys();
2979
    Vector relevantPaths = new Vector();
2980
    while (paths.hasMoreElements())
2981
      {
2982
        TreePath nextPath = (TreePath) paths.nextElement();
2983
        if (nodeStates.get(nextPath) == EXPANDED
2984
            && path.isDescendant(nextPath))
2985
          {
2986
            relevantPaths.add(nextPath);
2987
          }
2988
      }
2989
    return relevantPaths.elements();
2990
  }
2991
 
2992
  /**
2993
   * Returns the next table element (beginning from the row
2994
   * <code>startingRow</code> that starts with <code>prefix</code>.
2995
   * Searching is done in the direction specified by <code>bias</code>.
2996
   *
2997
   * @param prefix the prefix to search for in the cell values
2998
   * @param startingRow the index of the row where to start searching from
2999
   * @param bias the search direction, either {@link Position.Bias#Forward} or
3000
   *        {@link Position.Bias#Backward}
3001
   *
3002
   * @return the path to the found element or -1 if no such element has been
3003
   *         found
3004
   *
3005
   * @throws IllegalArgumentException if prefix is <code>null</code> or
3006
   *         startingRow is not valid
3007
   *
3008
   * @since 1.4
3009
   */
3010
  public TreePath getNextMatch(String prefix, int startingRow,
3011
                               Position.Bias bias)
3012
  {
3013
    if (prefix == null)
3014
      throw new IllegalArgumentException("The argument 'prefix' must not be"
3015
                                         + " null.");
3016
    if (startingRow < 0)
3017
      throw new IllegalArgumentException("The argument 'startingRow' must not"
3018
                                         + " be less than zero.");
3019
 
3020
    int size = getRowCount();
3021
    if (startingRow > size)
3022
      throw new IllegalArgumentException("The argument 'startingRow' must not"
3023
                                         + " be greater than the number of"
3024
                                         + " elements in the TreeModel.");
3025
 
3026
    TreePath foundPath = null;
3027
    if (bias == Position.Bias.Forward)
3028
      {
3029
        for (int i = startingRow; i < size; i++)
3030
          {
3031
            TreePath path = getPathForRow(i);
3032
            Object o = path.getLastPathComponent();
3033
            // FIXME: in the following call to convertValueToText the
3034
            // last argument (hasFocus) should be done right.
3035
            String item = convertValueToText(o, isRowSelected(i),
3036
                                             isExpanded(i), treeModel.isLeaf(o),
3037
                                             i, false);
3038
            if (item.startsWith(prefix))
3039
              {
3040
                foundPath = path;
3041
                break;
3042
              }
3043
          }
3044
      }
3045
    else
3046
      {
3047
        for (int i = startingRow; i >= 0; i--)
3048
          {
3049
            TreePath path = getPathForRow(i);
3050
            Object o = path.getLastPathComponent();
3051
            // FIXME: in the following call to convertValueToText the
3052
            // last argument (hasFocus) should be done right.
3053
            String item = convertValueToText(o, isRowSelected(i),
3054
                                             isExpanded(i), treeModel.isLeaf(o), i, false);
3055
            if (item.startsWith(prefix))
3056
              {
3057
                foundPath = path;
3058
                break;
3059
              }
3060
          }
3061
      }
3062
    return foundPath;
3063
  }
3064
 
3065
  /**
3066
   * Removes any paths in the current set of selected paths that are
3067
   * descendants of <code>path</code>. If <code>includePath</code> is set
3068
   * to <code>true</code> and <code>path</code> itself is selected, then
3069
   * it will be removed too.
3070
   *
3071
   * @param path the path from which selected descendants are to be removed
3072
   * @param includeSelected if <code>true</code> then <code>path</code> itself
3073
   *        will also be remove if it's selected
3074
   *
3075
   * @return <code>true</code> if something has been removed,
3076
   *         <code>false</code> otherwise
3077
   *
3078
   * @since 1.3
3079
   */
3080
  protected boolean removeDescendantSelectedPaths(TreePath path,
3081
                                                  boolean includeSelected)
3082
  {
3083
    boolean removedSomething = false;
3084
    TreePath[] selected = getSelectionPaths();
3085
    for (int index = 0; index < selected.length; index++)
3086
      {
3087
        if ((selected[index] == path && includeSelected)
3088
            || (selected[index].isDescendant(path)))
3089
          {
3090
            removeSelectionPath(selected[index]);
3091
            removedSomething = true;
3092
          }
3093
      }
3094
    return removedSomething;
3095
  }
3096
 
3097
  /**
3098
   * Removes any descendants of the TreePaths in toRemove that have been
3099
   * expanded.
3100
   *
3101
   * @param toRemove - Enumeration of TreePaths that need to be removed from
3102
   * cache of toggled tree paths.
3103
   */
3104
  protected void removeDescendantToggledPaths(Enumeration<TreePath> toRemove)
3105
  {
3106
    while (toRemove.hasMoreElements())
3107
      {
3108
        TreePath current = toRemove.nextElement();
3109
        Enumeration descendants = getDescendantToggledPaths(current);
3110
 
3111
        while (descendants.hasMoreElements())
3112
          {
3113
            TreePath currentDes = (TreePath) descendants.nextElement();
3114
            if (isExpanded(currentDes))
3115
                nodeStates.remove(currentDes);
3116
          }
3117
      }
3118
  }
3119
 
3120
  /**
3121
   * <p>
3122
   * Sent when the tree has changed enough that we need to resize the bounds,
3123
   * but not enough that we need to remove the expanded node set (e.g nodes were
3124
   * expanded or collapsed, or nodes were inserted into the tree). You should
3125
   * never have to invoke this, the UI will invoke this as it needs to.
3126
   * </p>
3127
   * <p>
3128
   * If the tree uses {@link DefaultTreeModel}, you must call
3129
   * {@link DefaultTreeModel#reload(TreeNode)} or
3130
   * {@link DefaultTreeModel#reload()} after adding or removing nodes. Following
3131
   * the official Java 1.5 API standard, just calling treeDidChange, repaint()
3132
   * or revalidate() does <i>not</i> update the tree appearance properly.
3133
   *
3134
   * @see DefaultTreeModel#reload()
3135
   */
3136
  public void treeDidChange()
3137
  {
3138
    repaint();
3139
  }
3140
 
3141
  /**
3142
   * Helper method for
3143
   * {@link LookAndFeel#installProperty(JComponent, String, Object)}.
3144
   *
3145
   * @param propertyName the name of the property
3146
   * @param value the value of the property
3147
   *
3148
   * @throws IllegalArgumentException if the specified property cannot be set
3149
   *         by this method
3150
   * @throws ClassCastException if the property value does not match the
3151
   *         property type
3152
   * @throws NullPointerException if <code>c</code> or
3153
   *         <code>propertyValue</code> is <code>null</code>
3154
   */
3155
  void setUIProperty(String propertyName, Object value)
3156
  {
3157
    if (propertyName.equals("rowHeight"))
3158
      {
3159
        if (! clientRowHeightSet)
3160
          {
3161
            setRowHeight(((Integer) value).intValue());
3162
            clientRowHeightSet = false;
3163
          }
3164
      }
3165
    else if (propertyName.equals("scrollsOnExpand"))
3166
      {
3167
        if (! clientScrollsOnExpandSet)
3168
          {
3169
            setScrollsOnExpand(((Boolean) value).booleanValue());
3170
            clientScrollsOnExpandSet = false;
3171
          }
3172
      }
3173
    else if (propertyName.equals("showsRootHandles"))
3174
      {
3175
        if (! clientShowsRootHandlesSet)
3176
          {
3177
            setShowsRootHandles(((Boolean) value).booleanValue());
3178
            clientShowsRootHandlesSet = false;
3179
          }
3180
      }
3181
    else
3182
      {
3183
        super.setUIProperty(propertyName, value);
3184
      }
3185
  }
3186
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.