Source for javax.swing.SortingFocusTraversalPolicy

   1: /* SortingFocusTraversalPolicy.java --
   2:    Copyright (C) 2005  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package javax.swing;
  40: 
  41: import java.awt.Component;
  42: import java.awt.Container;
  43: import java.util.Comparator;
  44: import java.util.Iterator;
  45: import java.util.TreeSet;
  46: 
  47: /**
  48:  * @author Graydon Hoare
  49:  * @author Michael Koch
  50:  *
  51:  * @since 1.4
  52:  */
  53: public class SortingFocusTraversalPolicy
  54:   extends InternalFrameFocusTraversalPolicy
  55: {
  56:   /**
  57:    * The comparator used to sort elements in the focus traversal cycle
  58:    * managed by this class.
  59:    */
  60:   Comparator comparator;
  61: 
  62:   /**
  63:    * <p>Whether or not to perform an "implicit DownCycle" when selecting
  64:    * successor components within a focus cycle.</p>
  65:    *
  66:    * <p>When this is true, requesting the "next" component following a
  67:    * component which is a focus cycle root (and, necessarily, a container)
  68:    * will enter the focus cycle root of that container, and return its
  69:    * default focus.</p>
  70:    *
  71:    * <p>When this property is false, requesting the "next" component will
  72:    * simply advance within the containing focus cycle, subject to the
  73:    * {@link #comparator} order and the {@link #accept} judgment.</p>
  74:    *
  75:    * @see #getImplicitDownCycleTraversal()
  76:    */
  77:   boolean implicitDownCycleTraversal = true;
  78: 
  79:   /**
  80:    * Creates a new <code>SortingFocusTraversalPolicy</code> with no
  81:    * comparator set.
  82:    */
  83:   protected SortingFocusTraversalPolicy()
  84:   {
  85:     // Do nothing here.
  86:   }
  87: 
  88:   /**
  89:    * Creates a new <code>SortingFocusTraversalPolicy</code> with the given
  90:    * comparator set.
  91:    *
  92:    * @param comparator the comparator to set
  93:    */
  94:   public SortingFocusTraversalPolicy(Comparator<? super Component> comparator)
  95:   {
  96:     this.comparator = comparator;
  97:   }
  98: 
  99:   /**
 100:    * Decide whether a component is an acceptable focus owner.
 101:    *
 102:    * @param comp The component which is a candidate for focus ownership.
 103:    *
 104:    * @return true if the component is focusable, displayable, visible, and
 105:    * enabled; otherwise false
 106:    */
 107:   protected boolean accept(Component comp)
 108:   {
 109:     return (comp.isVisible()
 110:             && comp.isDisplayable()
 111:             && comp.isEnabled()
 112:             && comp.isFocusable());
 113:   }
 114: 
 115:   /**
 116:    * Get the current value of the {@link #comparator} property.
 117:    *
 118:    * @return the current value of the property
 119:    *
 120:    * @see #setComparator
 121:    */
 122:   protected Comparator<? super Component> getComparator()
 123:   {
 124:     return comparator;
 125:   }
 126: 
 127:   /**
 128:    * Set the current value of the {@link #comparator} property.
 129:    *
 130:    * @param comparator the new value of the property
 131:    *
 132:    * @see #getComparator
 133:    */
 134:   protected void setComparator(Comparator<? super Component> comparator)
 135:   {
 136:     this.comparator = comparator;
 137:   }
 138: 
 139:   private TreeSet getSortedCycle(Container root, TreeSet set)
 140:   {
 141:     if (set == null)
 142:       set = (getComparator() == null
 143:              ? new TreeSet()
 144:              : new TreeSet(getComparator()));
 145: 
 146:     if (root != null)
 147:       {
 148:         Component[] comps = root.getComponents();
 149:         for (int i = 0; i < comps.length; ++i)
 150:           {
 151:             Component c = comps[i];
 152:             if (accept(c))
 153:               set.add(c);
 154:             if (c instanceof Container)
 155:               getSortedCycle((Container) c, set);
 156:           }
 157:       }
 158:     return set;
 159:   }
 160: 
 161:   /**
 162:    * Return the component which follows the specified component in this
 163:    * focus cycle, relative to the order imposed by {@link
 164:    * #comparator}. Candidate components are only considered if they are
 165:    * accepted by the {@link #accept} method.
 166:    *
 167:    * If {@link #getImplicitDownCycleTraversal} is <code>true</code> and the
 168:    * <code>comp</code> is a focus cycle root, an "implicit DownCycle"
 169:    * occurs and the method returns the
 170:    * <code>getDefaultComponent(comp)</code>.
 171:    *
 172:    * @param root the focus cycle root to search for a successor within
 173:    * @param comp the component to search for the successor of
 174:    *
 175:    * @return the component following the specified component under
 176:    * the specified root, or null if no such component is found
 177:    *
 178:    * @throws IllegalArgumentException if either argument is null, or
 179:    * if the root is not a focus cycle root of the component
 180:    */
 181:   public Component getComponentAfter(Container root,
 182:                                      Component comp)
 183:   {
 184:     if (comp == null || root == null || !comp.isFocusCycleRoot(root))
 185:       throw new IllegalArgumentException();
 186: 
 187:     if (getImplicitDownCycleTraversal()
 188:         && comp instanceof Container
 189:         && ((Container)comp).isFocusCycleRoot())
 190:       {
 191:         return getDefaultComponent((Container) comp);
 192:       }
 193: 
 194:     TreeSet set = getSortedCycle(root, null);
 195:     Iterator i = set.iterator();
 196:     while (i.hasNext())
 197:       {
 198:         Component c = (Component) i.next();
 199:         if (c != null && c.equals(comp))
 200:           {
 201:             if (i.hasNext())
 202:               return (Component) i.next();
 203:             break;
 204:           }
 205:       }
 206:     return null;
 207:   }
 208: 
 209: 
 210:   /**
 211:    * Return the component which precedes the specified component in this
 212:    * focus cycle, relative to the order imposed by {@link
 213:    * #comparator}. Candidate components are only considered if they are
 214:    * accepted by the {@link #accept} method.
 215:    *
 216:    * @param root the focus cycle root to search for a predecessor within
 217:    * @param comp the component to search for the predecessor of
 218:    *
 219:    * @return the component preceding the specified component under the
 220:    * specified root, or null if no such component is found
 221:    *
 222:    * @throws IllegalArgumentException if either argument is null, or
 223:    * if the root is not a focus cycle root of the component
 224:    */
 225:   public Component getComponentBefore(Container root,
 226:                                       Component comp)
 227:   {
 228:     if (comp == null || root == null || !comp.isFocusCycleRoot(root))
 229:       throw new IllegalArgumentException();
 230:     TreeSet set = getSortedCycle(root, null);
 231:     Iterator i = set.iterator();
 232:     Component prev = null;
 233:     while (i.hasNext())
 234:       {
 235:         Component c = (Component) i.next();
 236:         if (c != null && c.equals(comp))
 237:           break;
 238:         prev = c;
 239:       }
 240:     return prev;
 241:   }
 242: 
 243:   /**
 244:    * Return the default component of <code>root</code>, which is by default
 245:    * the same as the first component, returned by {@link
 246:    * #getFirstComponent}.
 247:    *
 248:    * @param root the focus cycle root to return the default component of
 249:    *
 250:    * @return the default focus component for <code>root</code>
 251:    *
 252:    * @throws IllegalArgumentException if root is null
 253:    */
 254:   public Component getDefaultComponent(Container root)
 255:   {
 256:     return getFirstComponent(root);
 257:   }
 258: 
 259:   /**
 260:    * Return the first focusable component of the focus cycle root
 261:    * <code>comp</code> under the ordering imposed by the {@link
 262:    * #comparator} property. Candidate components are only considered if
 263:    * they are accepted by the {@link #accept} method.
 264:    *
 265:    * @param root the focus cycle root to search for the first component of
 266:    *
 267:    * @return the first component under <code>root</code>, or null if
 268:    * no components are found.
 269:    *
 270:    * @throws IllegalArgumentException if root is null
 271:    */
 272:   public Component getFirstComponent(Container root)
 273:   {
 274:     if (root == null)
 275:       throw new IllegalArgumentException();
 276:     TreeSet set = getSortedCycle(root, null);
 277:     Iterator i = set.iterator();
 278:     if (i.hasNext())
 279:       return (Component) i.next();
 280:     return null;
 281:   }
 282: 
 283:   /**
 284:    * Return the last focusable component of the focus cycle root
 285:    * <code>comp</code> under the ordering imposed by the {@link
 286:    * #comparator} property. Candidate components are only considered if
 287:    * they are accepted by the {@link #accept} method.
 288:    *
 289:    * @param root the focus cycle root to search for the last component of
 290:    *
 291:    * @return the last component under <code>root</code>, or null if
 292:    * no components are found.
 293:    *
 294:    * @throws IllegalArgumentException if root is null
 295:    */
 296:   public Component getLastComponent(Container root)
 297:   {
 298:     if (root == null)
 299:       throw new IllegalArgumentException();
 300:     TreeSet set = getSortedCycle(root, null);
 301:     Iterator i = set.iterator();
 302:     Component last = null;
 303:     while (i.hasNext())
 304:       last = (Component) i.next();
 305:     return last;
 306:   }
 307: 
 308:   /**
 309:    * Return the current value of the {@link #implicitDownCycleTraversal}
 310:    * property.
 311:    *
 312:    * @return the current value of the property
 313:    *
 314:    * @see #setImplicitDownCycleTraversal
 315:    */
 316:   public boolean getImplicitDownCycleTraversal()
 317:   {
 318:     return implicitDownCycleTraversal;
 319:   }
 320: 
 321:   /**
 322:    * Set the current value of the {@link #implicitDownCycleTraversal}
 323:    * property.
 324:    *
 325:    * @param down the new value of the property
 326:    *
 327:    * @see #getImplicitDownCycleTraversal
 328:    */
 329:   public void setImplicitDownCycleTraversal(boolean down)
 330:   {
 331:     implicitDownCycleTraversal = down;
 332:   }
 333: }