home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 November / Chip_1998-11_cd.bin / tema / Cafe / jfc.bin / DefaultFocusManager.java < prev    next >
Text File  |  1998-02-26  |  12KB  |  315 lines

  1. /*
  2.  * @(#)DefaultFocusManager.java    1.6 98/01/30
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing;
  21.  
  22. /**
  23.  * Default swing focus manager implementation
  24.  *
  25.  * @version 1.6 01/30/98
  26.  * @author Arnaud Weber
  27.  */
  28. import java.awt.event.KeyEvent;
  29. import java.awt.Component;
  30. import java.awt.Container;
  31. import java.awt.event.ActionEvent;
  32. import java.awt.Window;
  33. import java.awt.Dialog;
  34. import java.awt.Rectangle;
  35. import java.util.Vector;
  36.  
  37. public class DefaultFocusManager extends FocusManager {
  38.  
  39.     /** This method is called by JComponents when a key event occurs.
  40.      *  JComponent gives key events to the focus manager
  41.      *  first, then to key listeners, then to the keyboard UI dispatcher.
  42.      *  This method should look at the key event and change the focused
  43.      *  component if the key event matches the receiver's focus manager
  44.      *  hot keys. For example the default focus manager will change the
  45.      *  focus if the key event matches TAB or Shift + TAB.
  46.      *  The focus manager should call consume() on <b>anEvent</b> if 
  47.      *  <code>anEvent</code> has been processed. 
  48.      *  <code>focusedComponent</code> is the component that currently has
  49.      *  the focus.
  50.      *  Note: FocusManager will receive KEY_PRESSED, KEY_RELEASED and KEY_TYPED
  51.      *  key events. If one event is consumed, all other events type should be consumed.
  52.      */
  53.     public void processKeyEvent(Component focusedComponent,KeyEvent anEvent) {
  54.         if(anEvent.getKeyCode() == KeyEvent.VK_TAB || anEvent.getKeyChar() == '\t') {
  55.             /** If the focused component manages focus, let it do so
  56.              *  if control is not pressed 
  57.              */
  58.             if(focusedComponent instanceof JComponent) {
  59.                 JComponent fc = (JComponent) focusedComponent;
  60.                 if(fc.isManagingFocus()) {
  61.                     if(!((anEvent.getModifiers() & ActionEvent.CTRL_MASK) == 
  62.                        ActionEvent.CTRL_MASK))
  63.                         return;
  64.                 }
  65.             }
  66.  
  67.             /** If this is not a key press, consume and return **/
  68.             if(anEvent.getID() != KeyEvent.KEY_PRESSED){
  69.                 anEvent.consume();
  70.                 return;
  71.             }
  72.  
  73.             if((anEvent.getModifiers() & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK) 
  74.                 focusPreviousComponent(focusedComponent);
  75.             else
  76.                 focusNextComponent(focusedComponent);
  77.             anEvent.consume();
  78.         }
  79.     }
  80.  
  81.     /** Cause the focus manager to set the focus on the next focusable component **/
  82.     public void focusNextComponent(Component aComponent) {
  83.         if(aComponent instanceof JComponent) {
  84.             JComponent fc  = (JComponent) aComponent;
  85.             Component nc;
  86.             Container  root = getFocusRoot(fc);
  87.             if(root != null) {
  88.                 nc = getFocusableComponentAfter(fc,root,true);
  89.                 if(nc != null) {
  90.                     if(nc instanceof JComponent)
  91.                         ((JComponent)nc).grabFocus();
  92.                     else
  93.                         nc.requestFocus();
  94.                 }
  95.             }
  96.         }
  97.     }
  98.  
  99.     /** Cause the focus manager to set the focus on the previous focusable component **/
  100.     public void focusPreviousComponent(Component aComponent) {
  101.         if(aComponent instanceof JComponent) {
  102.             JComponent fc  = (JComponent) aComponent;
  103.             Component nc;
  104.             Container root = getFocusRoot(fc);
  105.  
  106.             if(root != null) {
  107.                 nc = getFocusableComponentAfter(fc,root,false);
  108.                 if(nc != null) {
  109.                     if(nc instanceof JComponent)
  110.                         ((JComponent)nc).grabFocus();
  111.                     else
  112.                         nc.requestFocus();
  113.                 }
  114.             }
  115.         }
  116.     }
  117.  
  118.     Container getFocusRoot(Component c) {
  119.         Container p;
  120.         for(p = c.getParent() ; p != null ; p = p.getParent()) {
  121.             if(((p instanceof JComponent) && ((JComponent)p).isFocusCycleRoot()) ||
  122.                (p instanceof Window) || (p instanceof Dialog))
  123.                 return p;
  124.         }
  125.         return null;
  126.     }
  127.  
  128.     private Component getFocusableComponentAfter(Component focusedComponent,
  129.                                                  Container rootContainer,
  130.                                                  boolean moveForward) {
  131.         Component nextComponent;
  132.         Component initialComponent;
  133.  
  134.         nextComponent = initialComponent = focusedComponent;
  135.         do {
  136.             if(moveForward)
  137.                 nextComponent = getNextComponent(nextComponent,rootContainer,true);
  138.             else
  139.                 nextComponent = getPreviousComponent(nextComponent,rootContainer);
  140.  
  141.             if(nextComponent == null)
  142.                 break;
  143.             if(nextComponent == initialComponent)
  144.                 break;
  145.         } while(!(nextComponent.isFocusTraversable() && nextComponent.isEnabled()));
  146.  
  147.         return nextComponent;
  148.     }
  149.  
  150.    private Component getNextComponent(Component component,
  151.                                       Container root,
  152.                                       boolean canGoDown) {
  153.        Component nsv = null;
  154.        if(canGoDown && 
  155.           (((component instanceof JComponent)          && 
  156.             !((JComponent)component).isManagingFocus()) ||
  157.            !(component instanceof JComponent))         && 
  158.           ((component instanceof Container) && ((Container)component).getComponentCount() > 0)) {
  159.            return getFirstComponent((Container)component);
  160.        } else {
  161.            Container parent = component.getParent();
  162.            nsv = getComponentAfter(parent,component);
  163.            if(nsv != null)
  164.                return nsv;
  165.            if(parent == root)
  166.                return root;
  167.            else 
  168.                return getNextComponent(parent,root,false);
  169.        }
  170.    }
  171.  
  172.     private Component getPreviousComponent(Component component,Container root) {
  173.         Container parent = component.getParent();
  174.         if(component == root)
  175.             return getDeepestLastComponent(root);
  176.         else {
  177.             Component nsv = getComponentBefore(parent,component);
  178.             if(nsv != null)
  179.                 return getDeepestLastComponent(nsv);
  180.             else
  181.                 return parent;
  182.         }
  183.     }
  184.  
  185.     private Component getDeepestLastComponent(Component component) {
  186.         if((((component instanceof JComponent)          && 
  187.              !((JComponent)component).isManagingFocus()) ||
  188.             !(component instanceof JComponent))         && 
  189.            ((component instanceof Container) && ((Container)component).getComponentCount() > 0)) {
  190.             return getDeepestLastComponent(getLastComponent((Container) component));
  191.         } else
  192.             return component;
  193.     }
  194.     
  195.     /** Return the first component that should receive the focus **/
  196.     public Component getFirstComponent(Container aContainer) {
  197.         Component orderedChildren[] = childrenTabOrder(aContainer);
  198.         if(orderedChildren.length > 0)
  199.             return orderedChildren[0];
  200.         else
  201.             return null;
  202.     }
  203.  
  204.     /** Return the last component that should receive the focus **/
  205.     public Component getLastComponent(Container aContainer) {
  206.         Component orderedChildren[] = childrenTabOrder(aContainer);
  207.         if(orderedChildren.length > 0)
  208.             return orderedChildren[orderedChildren.length - 1];
  209.         else
  210.             return null;
  211.     }
  212.  
  213.     /** Return the component that should receive the focus before aComponent **/
  214.     public Component getComponentBefore(Container aContainer,Component aComponent) {
  215.         Component orderedChildren[] = childrenTabOrder(aContainer);
  216.         int i,c;
  217.         for(i=1,c=orderedChildren.length ; i < c ; i++) 
  218.             if(orderedChildren[i] == aComponent)
  219.                 return orderedChildren[i-1];
  220.         return null;
  221.     }
  222.  
  223.     /** Return the component the should receive the focus after aComponent **/
  224.     public Component getComponentAfter(Container aContainer,Component aComponent) {
  225.         Component orderedChildren[] = childrenTabOrder(aContainer);
  226.         int i,c;
  227.         for(i=0,c=orderedChildren.length - 1; i < c ; i++) 
  228.             if(orderedChildren[i] == aComponent)
  229.                 return orderedChildren[i+1];
  230.         return null;
  231.     }
  232.  
  233.     
  234.     /** Return true if <code>a</code> should be before <code>b</code> in the
  235.      * "tab" order. Override this method if you want to change the automatic
  236.      * "tab" order. 
  237.      * The default implementation will order tab to give a left to right, top
  238.      * down order. Override this method if another order is required.
  239.      */
  240.     public boolean compareTabOrder(Component a,Component b) {
  241.         Rectangle bounds;
  242.         int ay,by;
  243.         int ax,bx;
  244.         if(a instanceof JComponent) {
  245.             ay = ((JComponent)a).getY();
  246.             ax = ((JComponent)a).getX();
  247.         } else {
  248.             bounds = a.getBounds();
  249.             ay = bounds.y;
  250.             ax = bounds.x;
  251.         }
  252.  
  253.         if(b instanceof JComponent) {
  254.             by = ((JComponent)b).getY();
  255.             bx = ((JComponent)b).getX();
  256.         } else {
  257.             bounds = b.getBounds();
  258.             by = bounds.y;
  259.             bx = bounds.x;
  260.         }
  261.  
  262.         if(Math.abs(ay - by) < 10) {
  263.             return (ax < bx);
  264.         }
  265.         return (ay < by);
  266.     }
  267.  
  268.     Component[] childrenTabOrder(Container co) {
  269.         Component children[] = co.getComponents();
  270.         Component tmp;
  271.         int i,j,c;
  272.         boolean hasLink = false;
  273.  
  274.         /** Get the tab order from the geometry **/
  275.         for(i=0,c = children.length ; i < c ; i++) {
  276.             if(!hasLink && (children[i] instanceof JComponent) &&
  277.                ((JComponent)children[i]).getNextFocusableComponent() != null)
  278.                 hasLink = true;
  279.             for(j=i ; j < c ; j++) {
  280.                 if(i==j)
  281.                     continue;
  282.                 if(compareTabOrder(children[j],children[i])) {
  283.                     tmp = children[i];
  284.                     children[i] = children[j];
  285.                     children[j] = tmp;
  286.                 }                    
  287.             }
  288.         }
  289.  
  290.         if(hasLink) {
  291.             int index;
  292.             Component nextComponent;
  293.             Vector v = new Vector(c);
  294.             for(i=0; i < c ; i++) 
  295.                 v.addElement(children[i]);
  296.  
  297.             /** Take in account the next component link **/
  298.             for(i=0 ; i < c ; i++) {
  299.                 if((children[i] instanceof JComponent) &&
  300.                    (nextComponent = ((JComponent)children[i]).getNextFocusableComponent()) != null) {
  301.                     if((index = v.indexOf(nextComponent)) != -1) {
  302.                         v.removeElementAt(index);
  303.                         v.insertElementAt(nextComponent,i+1);
  304.                     }
  305.                 }
  306.             }
  307.  
  308.             for(i=0 ; i < c ; i++) 
  309.                 children[i] = (Component) v.elementAt(i);
  310.         }
  311.  
  312.         return children;
  313.     }
  314. }
  315.