home *** CD-ROM | disk | FTP | other *** search
Java Source | 1998-03-20 | 18.2 KB | 528 lines |
- /*
- * @(#)JLayeredPane.java 1.23 98/02/02
- *
- * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
- *
- * This software is the confidential and proprietary information of Sun
- * Microsystems, Inc. ("Confidential Information"). You shall not
- * disclose such Confidential Information and shall use it only in
- * accordance with the terms of the license agreement you entered into
- * with Sun.
- *
- * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
- * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
- * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
- * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
- * THIS SOFTWARE OR ITS DERIVATIVES.
- *
- */
- package java.awt.swing;
-
- import java.awt.Component;
- import java.util.Hashtable;
- import java.awt.Color;
- import java.awt.Graphics;
- import java.awt.Rectangle;
-
- import java.awt.accessibility.*;
-
- /**
- * <P>
- * JLayeredPane manages it's list of children like Container, but
- * allows for the definition of a several layers within itself. Children
- * in the same layer are managed exactly like the normal Container object,
- * with the added feature that children in higher layers display above
- * the children in lower layers.
- * Each layer is a distinct integer number.
- * <P>
- * The layer attribute can be set on a Component by passing an Integer object
- * during the add call. For example:
- * <PRE>
- * layeredPane.add(child, JLayeredPane.DEFAULT_LAYER);
- * or
- * layeredPane.add(child, new Integer(10));
- * </PRE>
- *
- * <P>
- * The layer attribute can also be set on a Component by calling
- * <PRE>
- * layeredPaneParent.setLayer(child, 10)
- * </PRE>
- * on the JLayeredPane that will be the parent of component. The layer
- * should be set before adding the child to the parent.
- * <P>
- * <PRE>
- * Higher number layers display above lower number layers.
- * Where numbers are the layers and letter indicate individual components:
- * A represenative list order looks like this:
- * 5a, 5b, 5c, 2a, 2b, 2c, 1a
- * Using the method add(Component, layer, position):
- * Calling add(5x, 5, -1) results in:
- * 5a, 5b, 5c, 5x, 2a, 2b, 2c, 1a
- * Calling add(5z, 5, 2) results in:
- * 5a, 5b, 5z, 5c, 5x, 2a, 2b, 2c, 1a
- * Calling add(3a, 3, 7) results in:
- * 5a, 5b, 5z, 5c, 5x, 3a, 2a, 2b, 2c, 1a
- * Using normal paint/event mechanics results in 1a appearing at the bottom
- * and 5a being above all other components.
- * </PRE>
- * Note that these layers are simply a logical construct and LayoutManagers
- * will affect all child components of this container without regard for
- * layer settings.
- * <p>
- * Warning: serialized objects of this class will not be compatible with
- * future swing releases. The current serialization support is appropriate
- * for short term storage or RMI between Swing1.0 applications. It will
- * not be possible to load serialized Swing1.0 objects with future releases
- * of Swing. The JDK1.2 release of Swing will be the compatibility
- * baseline for the serialized form of Swing objects.
- *
- * @version 1.23 02/02/98
- * @author David Kloba
- */
- public class JLayeredPane extends JComponent implements Accessible {
- /// Watch the values in getObjectForLayer()
- /** Convience object defining the Default layer. Equivalent to new Integer(0).*/
- public final static Integer DEFAULT_LAYER = new Integer(0);
- /** Convience object defining the Palette layer. Equivalent to new Integer(100).*/
- public final static Integer PALETTE_LAYER = new Integer(100);
- /** Convience object defining the Modal layer. Equivalent to new Integer(200).*/
- public final static Integer MODAL_LAYER = new Integer(200);
- /** Convience object defining the Popup layer. Equivalent to new Integer(300).*/
- public final static Integer POPUP_LAYER = new Integer(300);
- /** Convience object defining the Drag layer. Equivalent to new Integer(400).*/
- public final static Integer DRAG_LAYER = new Integer(400);
- /** Convience object defining the Frame Content layer.
- * This layer is normally only use to positon the contentPane and menuBar
- * components of JFrame.
- * Equivalent to new Integer(-30000).
- * @see JFrame
- */
- public final static Integer FRAME_CONTENT_LAYER = new Integer(-30000);
-
- public final static String LAYER_PROPERTY = "layeredContainerLayer";
- // Hashtable to store layer values for non-JComponent components
- private Hashtable componentToLayer;
- private boolean optimizedDrawingPossible = true;
-
-
- //////////////////////////////////////////////////////////////////////////////
- //// Container Override methods
- //////////////////////////////////////////////////////////////////////////////
- public JLayeredPane() {
- setLayout(null);
- }
-
- private void validateOptimizedDrawing() {
- boolean layeredComponentFound = false;
- synchronized(getTreeLock()) {
- int i,d;
- Integer layer = null;
-
- for(i=0,d=getComponentCount();i<d;i++) {
- layer = null;
- if(getComponent(i) instanceof JInternalFrame ||
- (getComponent(i) instanceof JComponent &&
- (layer = (Integer)((JComponent)getComponent(i)).getClientProperty(LAYER_PROPERTY)) != null)) {
- if(layer != null && layer.equals(FRAME_CONTENT_LAYER))
- continue;
- layeredComponentFound = true;
- break;
- }
- }
- }
-
- if(layeredComponentFound)
- optimizedDrawingPossible = false;
- else
- optimizedDrawingPossible = true;
- }
-
- protected void addImpl(Component comp, Object constraints, int index) {
- int layer = DEFAULT_LAYER.intValue();
- int pos;
-
- if(constraints instanceof Integer) {
- layer = ((Integer)constraints).intValue();
- setLayer(comp, layer);
- } else
- layer = getLayer(comp);
-
- pos = insertIndexForLayer(layer, index);
- super.addImpl(comp, constraints, pos);
- comp.validate();
- comp.repaint();
- validateOptimizedDrawing();
- }
-
- public void remove(int index) {
- Component c = getComponent(index);
- super.remove(index);
- validateOptimizedDrawing();
- }
-
- /**
- * Overridden to return false. The children of a LayeredPane can overlap.
- * @see JComponent#isOptimizedDrawingEnabled
- */
- public boolean isOptimizedDrawingEnabled() {
- return optimizedDrawingPossible;
- }
-
-
- //////////////////////////////////////////////////////////////////////////////
- //// New methods for managing layers
- //////////////////////////////////////////////////////////////////////////////
- /** This method will set the layer property on a JComponent, it
- * does not cause any side effects like setLayer(). (painting, add/remove, etc)
- * Normally you should use the instance method setLayer().
- */
- public static void putLayer(JComponent c, int layer) {
- /// MAKE SURE THIS AND setLayer(Component c, int layer, int position) are SYNCED
- Integer layerObj;
-
- layerObj = new Integer(layer);
- c.putClientProperty(LAYER_PROPERTY, layerObj);
- }
-
- /** This method will get the layer property on a JComponent, it
- * does not cause any side effects like setLayer(). (painting, add/remove, etc)
- * Normally you should use the instance method getLayer().
- */
- public static int getLayer(JComponent c) {
- Integer i;
- if((i = (Integer)c.getClientProperty(LAYER_PROPERTY)) != null)
- return i.intValue();
- return DEFAULT_LAYER.intValue();
- }
-
- /** Convience method for searching above <b>c</b> in the
- * component heirarchy and returns the first JLayeredPane it
- * finds. Will return null, in case a JLayeredPane cannot be found.
- * Note that all JFrames have a JLayeredPane as their rootPane.
- */
- public static JLayeredPane getLayeredPaneAbove(Component c) {
- if(c == null) return null;
-
- Component parent = c.getParent();
- while(parent != null && !(parent instanceof JLayeredPane))
- parent = parent.getParent();
- return (JLayeredPane)parent;
- }
-
- /** Sets the layer attribute on <b>c</b>. Should be called before
- * adding to parent.
- */
- public void setLayer(Component c, int layer) {
- setLayer(c, layer, -1);
- }
-
- /** Sets the layer attribute on <b>c</b>.
- */
- public void setLayer(Component c, int layer, int position) {
- Integer layerObj;
- layerObj = getObjectForLayer(layer);
-
- if(layer == getLayer(c) && position == getPosition(c)) {
- if(c instanceof JComponent)
- repaint(((JComponent)c)._bounds);
- else
- repaint(c.getBounds());
- return;
- }
-
- /// MAKE SURE THIS AND putLayer(JComponent c, int layer) are SYNCED
- if(c instanceof JComponent)
- ((JComponent)c).putClientProperty(LAYER_PROPERTY, layerObj);
- else
- getComponentToLayer().put(LAYER_PROPERTY, layerObj);
-
- if(c.getParent() == null || c.getParent() != this) {
- if(c instanceof JComponent)
- repaint(((JComponent)c)._bounds);
- else
- repaint(c.getBounds());
- return;
- }
-
- // Remove the Component and re-add after re-setting the layer
- // this is necessary now because I have no access to the
- // components[] in Container, to reorder things.
- remove(c);
-
- // ALERT passing NULL here for the constraints may be bad
- // the current hacks to fix this smell bad right now.
- // Cannot override
- add(c, null, position);
- if(c instanceof JComponent)
- repaint(((JComponent)c)._bounds);
- else
- repaint(c.getBounds());
- }
-
- /** Returns the layer attribute for this Component <b>c</b>.*/
- public int getLayer(Component c) {
- Integer i;
- if(c instanceof JComponent)
- i = (Integer)((JComponent)c).getClientProperty(LAYER_PROPERTY);
- else
- i = (Integer)getComponentToLayer().get(LAYER_PROPERTY);
-
- if(i == null)
- return DEFAULT_LAYER.intValue();
- return i.intValue();
- }
-
- /** Returns the index of this Component <b>c</b>.
- * This is the absolute index, ignoring layers.
- */
- public int getIndexOf(Component c) {
- int i, count;
-
- count = getComponentCount();
- for(i = 0; i < count; i++) {
- if(c == getComponent(i))
- return i;
- }
- return -1;
- }
- /** Moves the component to position 0 within it's current layer. */
- public void moveToFront(Component c) {
- setPosition(c, 0);
- }
-
- /** Moves the component to position -1 within it's current layer. */
- public void moveToBack(Component c) {
- setPosition(c, getComponentCountInLayer(getLayer(c)));
- }
-
- /** Moves the component to <b>position</b> within it's current layer. */
- public void setPosition(Component c, int position) {
- setLayer(c, getLayer(c), position);
- }
-
- /** Relative position with the component's layer. */
- public int getPosition(Component c) {
- int i, count, startLayer, curLayer, startLocation, pos = 0;
-
- count = getComponentCount();
- startLocation = getIndexOf(c);
-
- if(startLocation == -1)
- return -1;
-
- startLayer = getLayer(c);
- for(i = startLocation - 1; i >= 0; i--) {
- curLayer = getLayer(getComponent(i));
- if(curLayer == startLayer)
- pos++;
- else
- return pos;
- }
- return pos;
- }
-
- /** Returns the highest layer value from all current children.
- * Returns 0 if there are not children.
- */
- public int highestLayer() {
- if(getComponentCount() > 0)
- return getLayer(getComponent(0));
- return 0;
- }
-
- /** Returns the lowest layer value from all current children.
- * Returns 0 if there are not children.
- */
- public int lowestLayer() {
- int count = getComponentCount();
- if(count > 0)
- return getLayer(getComponent(count-1));
- return 0;
- }
-
- /** Returns the number of children currently in <b>layer</b>.
- */
- public int getComponentCountInLayer(int layer) {
- int i, count, curLayer;
- int layerCount = 0;
-
- count = getComponentCount();
- for(i = 0; i < count; i++) {
- curLayer = getLayer(getComponent(i));
- if(curLayer == layer) {
- layerCount++;
- /// Short circut the counting when we have them all
- } else if(layerCount > 0 || curLayer < layer) {
- break;
- }
- }
-
- return layerCount;
- }
-
- /** Returns an array of the components in <b>layer</b>.
- */
- public Component[] getComponentsInLayer(int layer) {
- int i, count, curLayer;
- int layerCount = 0;
- Component[] results;
-
- results = new Component[getComponentCountInLayer(layer)];
- count = getComponentCount();
- for(i = 0; i < count; i++) {
- curLayer = getLayer(getComponent(i));
- if(curLayer == layer) {
- results[layerCount++] = getComponent(i);
- /// Short circut the counting when we have them all
- } else if(layerCount > 0 || curLayer < layer) {
- break;
- }
- }
-
- return results;
- }
-
- public void paint(Graphics g) {
- if(isOpaque()) {
- Rectangle r = g.getClipBounds();
- Color c = getBackground();
- if(c == null)
- c = Color.lightGray;
- g.setColor(c);
- g.fillRect(r.x, r.y, r.width, r.height);
- }
- super.paint(g);
- }
-
- //////////////////////////////////////////////////////////////////////////////
- //// Implementation Details
- //////////////////////////////////////////////////////////////////////////////
-
- protected Hashtable getComponentToLayer() {
- if(componentToLayer == null)
- componentToLayer = new Hashtable(4);
- return componentToLayer;
- }
-
- protected Integer getObjectForLayer(int layer) {
- Integer layerObj;
- switch(layer) {
- case 0:
- layerObj = DEFAULT_LAYER;
- break;
- case 100:
- layerObj = PALETTE_LAYER;
- break;
- case 200:
- layerObj = MODAL_LAYER;
- break;
- case 300:
- layerObj = POPUP_LAYER;
- break;
- case 400:
- layerObj = DRAG_LAYER;
- break;
- default:
- layerObj = new Integer(layer);
- }
- return layerObj;
- }
-
- /** Primative method that determines the proper location to
- * insert a new child based on layer and position requests.
- */
- protected int insertIndexForLayer(int layer, int position) {
- int i, count, curLayer;
- int layerStart = -1;
- int layerEnd = -1;
-
- count = getComponentCount();
- for(i = 0; i < count; i++) {
- curLayer = getLayer(getComponent(i));
- if(layerStart == -1 && curLayer == layer) {
- layerStart = i;
- }
- if(curLayer < layer ) {
- if(i == 0) {
- // layer is greater than any current layer
- // [ ASSERT(layer > highestLayer()) ]
- layerStart = 0;
- layerEnd = 0;
- } else {
- layerEnd = i;
- }
- break;
- }
- }
-
- // layer requested is lower than any current layer
- // [ ASSERT(layer < lowestLayer()) ]
- // put it on the bottom of the stack
- if(layerStart == -1 && layerEnd == -1)
- return count;
-
- // In the case of a single layer entry handle the degenerative cases
- if(layerStart != -1 && layerEnd == -1)
- layerEnd = count;
-
- if(layerEnd != -1 && layerStart == -1)
- layerStart = layerEnd;
-
- // If we are adding to the bottom, return the last element
- if(position == -1)
- return layerEnd;
-
- // Otherwise make sure the requested position falls in the
- // proper range
- if(position > -1 && layerStart + position <= layerEnd)
- return layerStart + position;
-
- // Otherwise return the end of the layer
- return layerEnd;
- }
-
- /////////////////
- // Accessibility support
- ////////////////
-
- /**
- * Get the AccessibleContext associated with this JComponent
- *
- * @return the AccessibleContext of this JComponent
- */
- public AccessibleContext getAccessibleContext() {
- if (accessibleContext == null) {
- accessibleContext = new AccessibleJLayeredPane();
- }
- return accessibleContext;
- }
-
- /**
- * The class used to obtain the accessible role for this object.
- * <p>
- * Warning: serialized objects of this class will not be compatible with
- * future swing releases. The current serialization support is appropriate
- * for short term storage or RMI between Swing1.0 applications. It will
- * not be possible to load serialized Swing1.0 objects with future releases
- * of Swing. The JDK1.2 release of Swing will be the compatibility
- * baseline for the serialized form of Swing objects.
- */
- protected class AccessibleJLayeredPane extends AccessibleJComponent {
-
- /**
- * Get the role of this object.
- *
- * @return an instance of AccessibleRole describing the role of the
- * object
- * @see AccessibleRole
- */
- public AccessibleRole getAccessibleRole() {
- return AccessibleRole.LAYERED_PANE;
- }
- }
- }
-
-
-