home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 1998 November
/
Chip_1998-11_cd.bin
/
tema
/
Cafe
/
jfc.bin
/
JLayeredPane.java
< prev
next >
Wrap
Text File
|
1998-02-26
|
18KB
|
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 com.sun.java.swing;
import java.awt.Component;
import java.util.Hashtable;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import com.sun.java.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;
}
}
}