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

  1. /*
  2.  * @(#)JLayeredPane.java    1.23 98/02/02
  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. import java.awt.Component;
  23. import java.util.Hashtable;
  24. import java.awt.Color;
  25. import java.awt.Graphics;
  26. import java.awt.Rectangle;
  27.  
  28. import com.sun.java.accessibility.*;
  29.  
  30. /**
  31.  * <P>
  32.  * JLayeredPane manages it's list of children like Container, but
  33.  * allows for the definition of a several layers within itself. Children
  34.  * in the same layer are managed exactly like the normal Container object,
  35.  * with the added feature that children in higher layers display above 
  36.  * the children in lower layers.  
  37.  * Each layer is a distinct integer number. 
  38.  * <P>
  39.  * The layer attribute can be set on a Component by passing an Integer object
  40.  * during the add call. For example:
  41.  * <PRE>
  42.  *     layeredPane.add(child, JLayeredPane.DEFAULT_LAYER);
  43.  * or
  44.  *     layeredPane.add(child, new Integer(10));
  45.  * </PRE>
  46.  * 
  47.  * <P>
  48.  * The layer attribute can also be set on a Component by calling 
  49.  * <PRE>
  50.  *     layeredPaneParent.setLayer(child, 10)
  51.  * </PRE>
  52.  * on the JLayeredPane that will be the parent of component. The layer
  53.  * should be set before adding the child to the parent.
  54.  * <P>
  55.  * <PRE>
  56.  * Higher number layers display above lower number layers.
  57.  * Where numbers are the layers and letter indicate individual components:
  58.  * A represenative list order looks like this:
  59.  *       5a, 5b, 5c, 2a, 2b, 2c, 1a
  60.  * Using the method add(Component, layer, position):
  61.  * Calling add(5x, 5, -1) results in:
  62.  *       5a, 5b, 5c, 5x, 2a, 2b, 2c, 1a
  63.  * Calling add(5z, 5, 2) results in:
  64.  *       5a, 5b, 5z, 5c, 5x, 2a, 2b, 2c, 1a
  65.  * Calling add(3a, 3, 7) results in:
  66.  *       5a, 5b, 5z, 5c, 5x, 3a, 2a, 2b, 2c, 1a
  67.  * Using normal paint/event mechanics results in 1a appearing at the bottom
  68.  * and 5a being above all other components.
  69.  * </PRE>
  70.  * Note that these layers are simply a logical construct and LayoutManagers
  71.  * will affect all child components of this container without regard for
  72.  * layer settings.
  73.  * <p>
  74.  * Warning: serialized objects of this class will not be compatible with
  75.  * future swing releases.  The current serialization support is appropriate 
  76.  * for short term storage or RMI between Swing1.0 applications.  It will
  77.  * not be possible to load serialized Swing1.0 objects with future releases
  78.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  79.  * baseline for the serialized form of Swing objects.
  80.  * 
  81.  * @version 1.23 02/02/98
  82.  * @author David Kloba
  83.  */
  84. public class JLayeredPane extends JComponent implements Accessible {
  85.     /// Watch the values in getObjectForLayer()
  86.     /** Convience object defining the Default layer. Equivalent to new Integer(0).*/
  87.     public final static Integer DEFAULT_LAYER = new Integer(0);
  88.     /** Convience object defining the Palette layer. Equivalent to new Integer(100).*/
  89.     public final static Integer PALETTE_LAYER = new Integer(100);
  90.     /** Convience object defining the Modal layer. Equivalent to new Integer(200).*/
  91.     public final static Integer MODAL_LAYER = new Integer(200);
  92.     /** Convience object defining the Popup layer. Equivalent to new Integer(300).*/
  93.     public final static Integer POPUP_LAYER = new Integer(300);
  94.     /** Convience object defining the Drag layer. Equivalent to new Integer(400).*/
  95.     public final static Integer DRAG_LAYER = new Integer(400);
  96.     /** Convience object defining the Frame Content layer. 
  97.       * This layer is normally only use to positon the contentPane and menuBar 
  98.       * components of JFrame.
  99.       * Equivalent to new Integer(-30000).
  100.       * @see JFrame
  101.       */
  102.     public final static Integer FRAME_CONTENT_LAYER = new Integer(-30000);
  103.  
  104.     public final static String LAYER_PROPERTY = "layeredContainerLayer";
  105.     // Hashtable to store layer values for non-JComponent components
  106.     private Hashtable componentToLayer;
  107.     private boolean optimizedDrawingPossible = true;
  108.  
  109.  
  110. //////////////////////////////////////////////////////////////////////////////
  111. //// Container Override methods 
  112. //////////////////////////////////////////////////////////////////////////////
  113.     public JLayeredPane() {
  114.         setLayout(null);
  115.     }
  116.  
  117.     private void validateOptimizedDrawing() {
  118.         boolean layeredComponentFound = false;
  119.         synchronized(getTreeLock()) {
  120.             int i,d;
  121.             Integer layer = null;
  122.  
  123.             for(i=0,d=getComponentCount();i<d;i++) {
  124.                 layer = null;
  125.                 if(getComponent(i) instanceof JInternalFrame ||
  126.                    (getComponent(i) instanceof JComponent &&
  127.                     (layer = (Integer)((JComponent)getComponent(i)).getClientProperty(LAYER_PROPERTY)) != null)) {
  128.                     if(layer != null && layer.equals(FRAME_CONTENT_LAYER))
  129.                         continue;
  130.                     layeredComponentFound = true;
  131.                     break;
  132.                 }
  133.             }
  134.         }
  135.         
  136.         if(layeredComponentFound)
  137.             optimizedDrawingPossible = false;
  138.         else
  139.             optimizedDrawingPossible = true;
  140.     }
  141.     
  142.     protected void addImpl(Component comp, Object constraints, int index) {
  143.     int layer = DEFAULT_LAYER.intValue();
  144.         int pos;
  145.  
  146.     if(constraints instanceof Integer) {
  147.         layer = ((Integer)constraints).intValue();
  148.         setLayer(comp, layer);
  149.     } else
  150.         layer = getLayer(comp);
  151.  
  152.         pos = insertIndexForLayer(layer, index);
  153.         super.addImpl(comp, constraints, pos);
  154.         comp.validate();
  155.         comp.repaint();
  156.         validateOptimizedDrawing();
  157.     }
  158.  
  159.     public void remove(int index) {
  160.         Component c = getComponent(index);
  161.         super.remove(index);
  162.         validateOptimizedDrawing();
  163.     }
  164.  
  165.     /**
  166.      * Overridden to return false.  The children of a LayeredPane can overlap.
  167.      * @see JComponent#isOptimizedDrawingEnabled
  168.      */
  169.     public boolean isOptimizedDrawingEnabled() {
  170.         return optimizedDrawingPossible;
  171.     }
  172.  
  173.  
  174. //////////////////////////////////////////////////////////////////////////////
  175. //// New methods for managing layers
  176. //////////////////////////////////////////////////////////////////////////////
  177.     /** This method will set the layer property on a JComponent, it
  178.       * does not cause any side effects like setLayer(). (painting, add/remove, etc)
  179.       * Normally you should use the instance method setLayer().
  180.       */
  181.     public static void putLayer(JComponent c, int layer) {
  182.     /// MAKE SURE THIS AND setLayer(Component c, int layer, int position)  are SYNCED
  183.         Integer layerObj;
  184.  
  185.         layerObj = new Integer(layer);
  186.         c.putClientProperty(LAYER_PROPERTY, layerObj);
  187.     }
  188.  
  189.     /** This method will get the layer property on a JComponent, it
  190.       * does not cause any side effects like setLayer(). (painting, add/remove, etc)
  191.       * Normally you should use the instance method getLayer().
  192.       */
  193.     public static int getLayer(JComponent c) {
  194.     Integer i;
  195.     if((i = (Integer)c.getClientProperty(LAYER_PROPERTY)) != null)
  196.         return i.intValue();
  197.     return DEFAULT_LAYER.intValue();
  198.     }
  199.  
  200.     /** Convience method for searching above <b>c</b> in the 
  201.       * component heirarchy and returns the first JLayeredPane it
  202.       * finds. Will return null, in case a JLayeredPane cannot be found.
  203.       * Note that all JFrames have a JLayeredPane as their rootPane.
  204.       */
  205.     public static JLayeredPane getLayeredPaneAbove(Component c) {
  206.     if(c == null) return null;
  207.     
  208.     Component parent = c.getParent();
  209.     while(parent != null && !(parent instanceof JLayeredPane))
  210.         parent = parent.getParent();
  211.     return (JLayeredPane)parent;
  212.     }
  213.  
  214.     /** Sets the layer attribute on <b>c</b>. Should be called before 
  215.       * adding to parent. 
  216.       */
  217.     public void setLayer(Component c, int layer)  {
  218.         setLayer(c, layer, -1);
  219.     }
  220.  
  221.     /** Sets the layer attribute on <b>c</b>. 
  222.       */
  223.     public void setLayer(Component c, int layer, int position)  {
  224.         Integer layerObj;
  225.         layerObj = getObjectForLayer(layer);
  226.  
  227.         if(layer == getLayer(c) && position == getPosition(c)) {
  228.             if(c instanceof JComponent)
  229.                 repaint(((JComponent)c)._bounds);
  230.             else
  231.                 repaint(c.getBounds());
  232.             return;
  233.         }
  234.     
  235.     /// MAKE SURE THIS AND putLayer(JComponent c, int layer) are SYNCED
  236.         if(c instanceof JComponent)
  237.             ((JComponent)c).putClientProperty(LAYER_PROPERTY, layerObj);
  238.         else
  239.             getComponentToLayer().put(LAYER_PROPERTY, layerObj);
  240.     
  241.         if(c.getParent() == null || c.getParent() != this)      {
  242.             if(c instanceof JComponent)
  243.                 repaint(((JComponent)c)._bounds);
  244.             else
  245.                 repaint(c.getBounds());
  246.             return;
  247.         }
  248.  
  249.         // Remove the Component and re-add after re-setting the layer
  250.         // this is necessary now because I have no access to the
  251.         // components[] in Container, to reorder things.
  252.         remove(c);
  253.  
  254.         // ALERT passing NULL here for the constraints may be bad
  255.         // the current hacks to fix this smell bad right now. 
  256.         // Cannot override 
  257.         add(c, null, position);
  258.         if(c instanceof JComponent)
  259.             repaint(((JComponent)c)._bounds);
  260.         else
  261.             repaint(c.getBounds());
  262.     }
  263.  
  264.     /** Returns the layer attribute for this Component <b>c</b>.*/
  265.     public int getLayer(Component c) {
  266.         Integer i;
  267.         if(c instanceof JComponent)
  268.             i = (Integer)((JComponent)c).getClientProperty(LAYER_PROPERTY);
  269.         else
  270.             i = (Integer)getComponentToLayer().get(LAYER_PROPERTY);
  271.  
  272.         if(i == null)
  273.             return DEFAULT_LAYER.intValue();
  274.         return i.intValue();
  275.     }
  276.  
  277.     /** Returns the index of this Component <b>c</b>. 
  278.       * This is the absolute index, ignoring layers. 
  279.       */
  280.     public int getIndexOf(Component c) {
  281.         int i, count;
  282.         
  283.         count = getComponentCount();    
  284.         for(i = 0; i < count; i++) {
  285.             if(c == getComponent(i))
  286.                 return i;
  287.         }
  288.         return -1;
  289.     }
  290.     /** Moves the component to position 0 within it's current layer. */
  291.     public void moveToFront(Component c) {
  292.         setPosition(c, 0);
  293.     }
  294.  
  295.     /** Moves the component to position -1 within it's current layer. */
  296.     public void moveToBack(Component c) {
  297.         setPosition(c, getComponentCountInLayer(getLayer(c)));
  298.     }
  299.  
  300.     /** Moves the component to <b>position</b> within it's current layer. */
  301.     public void setPosition(Component c, int position) {
  302.         setLayer(c, getLayer(c), position);
  303.     }
  304.  
  305.     /** Relative position with the component's layer. */
  306.     public int getPosition(Component c) {
  307.         int i, count, startLayer, curLayer, startLocation, pos = 0;
  308.         
  309.         count = getComponentCount();
  310.         startLocation = getIndexOf(c);
  311.  
  312.         if(startLocation == -1)
  313.             return -1;
  314.         
  315.         startLayer = getLayer(c);
  316.         for(i = startLocation - 1; i >= 0; i--) {
  317.             curLayer = getLayer(getComponent(i));               
  318.             if(curLayer == startLayer)
  319.                 pos++;
  320.             else
  321.                 return pos;
  322.         }
  323.         return pos;
  324.     }
  325.  
  326.     /** Returns the highest layer value from all current children.
  327.       * Returns 0 if there are not children.
  328.       */
  329.     public int highestLayer() {
  330.         if(getComponentCount() > 0)
  331.             return getLayer(getComponent(0));           
  332.         return 0;
  333.     }
  334.  
  335.     /** Returns the lowest layer value from all current children.
  336.       * Returns 0 if there are not children.
  337.       */
  338.     public int lowestLayer() {
  339.         int count = getComponentCount();
  340.         if(count > 0)
  341.             return getLayer(getComponent(count-1));             
  342.         return 0;
  343.     }
  344.  
  345.     /** Returns the number of children currently in <b>layer</b>.
  346.       */
  347.     public int getComponentCountInLayer(int layer) {
  348.         int i, count, curLayer;
  349.         int layerCount = 0;
  350.         
  351.         count = getComponentCount();
  352.         for(i = 0; i < count; i++) {
  353.             curLayer = getLayer(getComponent(i));               
  354.             if(curLayer == layer) {
  355.                 layerCount++;
  356.             /// Short circut the counting when we have them all
  357.             } else if(layerCount > 0 || curLayer < layer) {
  358.                 break;
  359.             }
  360.         }
  361.         
  362.         return layerCount;
  363.     }
  364.  
  365.     /** Returns an array of the components in <b>layer</b>.
  366.       */
  367.     public Component[] getComponentsInLayer(int layer) {
  368.         int i, count, curLayer;
  369.         int layerCount = 0;
  370.         Component[] results;
  371.         
  372.         results = new Component[getComponentCountInLayer(layer)];
  373.         count = getComponentCount();
  374.         for(i = 0; i < count; i++) {
  375.             curLayer = getLayer(getComponent(i));               
  376.             if(curLayer == layer) {
  377.                 results[layerCount++] = getComponent(i);
  378.             /// Short circut the counting when we have them all
  379.             } else if(layerCount > 0 || curLayer < layer) {
  380.                 break;
  381.             }
  382.         }
  383.         
  384.         return results;
  385.     }
  386.  
  387.     public void paint(Graphics g) {
  388.     if(isOpaque()) {
  389.         Rectangle r = g.getClipBounds();
  390.         Color c = getBackground();
  391.         if(c == null)
  392.         c = Color.lightGray;
  393.         g.setColor(c);
  394.         g.fillRect(r.x, r.y, r.width, r.height);
  395.     }
  396.     super.paint(g);
  397.     }
  398.  
  399. //////////////////////////////////////////////////////////////////////////////
  400. //// Implementation Details
  401. //////////////////////////////////////////////////////////////////////////////
  402.  
  403.     protected Hashtable getComponentToLayer() {
  404.         if(componentToLayer == null)
  405.             componentToLayer = new Hashtable(4);
  406.         return componentToLayer;
  407.     }
  408.     
  409.     protected Integer getObjectForLayer(int layer) {
  410.         Integer layerObj;
  411.         switch(layer) {
  412.         case 0:
  413.             layerObj = DEFAULT_LAYER;
  414.             break;
  415.         case 100:
  416.             layerObj = PALETTE_LAYER;
  417.             break;
  418.         case 200:
  419.             layerObj = MODAL_LAYER;
  420.             break;
  421.         case 300:
  422.             layerObj = POPUP_LAYER;
  423.             break;
  424.         case 400:
  425.             layerObj = DRAG_LAYER;
  426.             break;
  427.         default:
  428.             layerObj = new Integer(layer);
  429.         }
  430.         return layerObj;
  431.     }
  432.  
  433.     /** Primative method that determines the proper location to
  434.       * insert a new child based on layer and position requests.
  435.       */
  436.     protected int insertIndexForLayer(int layer, int position) {
  437.         int i, count, curLayer;
  438.         int layerStart = -1;
  439.         int layerEnd = -1;
  440.         
  441.         count = getComponentCount();
  442.         for(i = 0; i < count; i++) {
  443.             curLayer = getLayer(getComponent(i));               
  444.             if(layerStart == -1 && curLayer == layer) {
  445.                 layerStart = i;
  446.             }   
  447.             if(curLayer < layer ) {
  448.                 if(i == 0) { 
  449.                     // layer is greater than any current layer  
  450.                     // [ ASSERT(layer > highestLayer()) ] 
  451.                     layerStart = 0;
  452.                     layerEnd = 0;
  453.                 } else {
  454.                     layerEnd = i;
  455.                 }
  456.                 break;
  457.             }
  458.         }
  459.  
  460.         // layer requested is lower than any current layer
  461.         // [ ASSERT(layer < lowestLayer()) ] 
  462.         // put it on the bottom of the stack
  463.         if(layerStart == -1 && layerEnd == -1)
  464.             return count;
  465.  
  466.         // In the case of a single layer entry handle the degenerative cases
  467.         if(layerStart != -1 && layerEnd == -1)
  468.             layerEnd = count;
  469.         
  470.         if(layerEnd != -1 && layerStart == -1)
  471.             layerStart = layerEnd;
  472.         
  473.         // If we are adding to the bottom, return the last element
  474.         if(position == -1)
  475.             return layerEnd;
  476.         
  477.         // Otherwise make sure the requested position falls in the 
  478.         // proper range
  479.         if(position > -1 && layerStart + position <= layerEnd)
  480.             return layerStart + position;
  481.         
  482.         // Otherwise return the end of the layer
  483.         return layerEnd;
  484.     }
  485.  
  486. /////////////////
  487. // Accessibility support
  488. ////////////////
  489.  
  490.     /**
  491.      * Get the AccessibleContext associated with this JComponent
  492.      *
  493.      * @return the AccessibleContext of this JComponent
  494.      */
  495.     public AccessibleContext getAccessibleContext() {
  496.     if (accessibleContext == null) {
  497.         accessibleContext = new AccessibleJLayeredPane();
  498.         }
  499.     return accessibleContext;
  500.     }
  501.  
  502.     /**
  503.      * The class used to obtain the accessible role for this object.
  504.      * <p>
  505.      * Warning: serialized objects of this class will not be compatible with
  506.      * future swing releases.  The current serialization support is appropriate
  507.      * for short term storage or RMI between Swing1.0 applications.  It will
  508.      * not be possible to load serialized Swing1.0 objects with future releases
  509.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  510.      * baseline for the serialized form of Swing objects.
  511.      */
  512.     protected class AccessibleJLayeredPane extends AccessibleJComponent {
  513.  
  514.     /**
  515.      * Get the role of this object.
  516.      *
  517.      * @return an instance of AccessibleRole describing the role of the 
  518.      * object
  519.      * @see AccessibleRole
  520.      */
  521.     public AccessibleRole getAccessibleRole() {
  522.         return AccessibleRole.LAYERED_PANE;
  523.     }
  524.     }
  525. }
  526.  
  527.  
  528.