libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / javax / swing / JLayeredPane.java
blobd981788ec7de5162a913a46c0da8c9a398a5689c
1 /* JLayeredPane.java --
2 Copyright (C) 2002, 2004 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
39 package javax.swing;
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Container;
44 import java.awt.Graphics;
45 import java.awt.Rectangle;
46 import java.util.ArrayList;
47 import java.util.Hashtable;
49 import javax.accessibility.Accessible;
50 import javax.accessibility.AccessibleContext;
51 import javax.accessibility.AccessibleRole;
53 /**
54 * A container that adds depth to the usual <code>Container</code> semantics.
55 * Each child component of a <code>Layered Pane</code> is placed within one
56 * of several layers. <code>JLayeredPane</code> defines a set of standard
57 * layers. The pre-defined sets are (in the order from button to top):
59 * <dl>
60 * <dt>{@link #DEFAULT_LAYER}</dt>
61 * <dd>The layer where most of the normal components are placed. This
62 * is the bottommost layer.</dd>
64 * <dt>{@link #PALETTE_LAYER}</dt>
65 * <dd>Palette windows are placed in this layer.</dd>
67 * <dt>{@link #MODAL_LAYER}</dt>
68 * <dd>The layer where internal modal dialog windows are placed.</dd>
70 * <dt>{@link #POPUP_LAYER}</dt>
71 * <dd>The layer for popup menus</dd>
73 * <dt>{@link #DRAG_LAYER}</dt>
74 * <dd>Components that are beeing dragged are temporarily placed in
75 * this layer.</dd>
76 * </dl>
78 * <p>A child is in exactly one of these layers at any time, though there may
79 * be other layers if someone creates them.</p>
81 * <p>You can add a component to a specific layer using the
82 * {@link Container#add(Component, Object)} method. I.e.
83 * <code>layeredPane.add(comp, JLayeredPane.MODAL_LAYER)</code> will add the
84 * component <code>comp</code> to the modal layer of <code>layeredPane</code>.
85 * </p>
87 * <p>To change the layer of a component that is already a child of
88 * a <code>JLayeredPane</code>, use the {@link #setLayer(Component, int)}
89 * method.</p>
91 * <p>The purpose of this class is to translate this view of "layers" into a
92 * contiguous array of components: the one held in our ancestor,
93 * {@link java.awt.Container}.</p>
95 * <p>There is a precise set of words we will use to refer to numbers within
96 * this class:</p>
98 * <dl>
99 * <dt>Component Index:</dt>
100 * <dd>An offset into the <code>component</code> array held in our ancestor,
101 * {@link java.awt.Container}, from <code>[0 .. component.length)</code>. The drawing
102 * rule with indices is that 0 is drawn last.</dd>
104 * <dt>Layer Number:</dt>
105 * <dd>A general <code>int</code> specifying a layer within this component. Negative
106 * numbers are drawn first, then layer 0, then positive numbered layers, in
107 * ascending order.</dd>
109 * <dt>Position:</dt>
110 * <dd>An offset into a layer's "logical drawing order". Layer position 0
111 * is drawn last. Layer position -1 is a synonym for the first layer
112 * position (the logical "bottom").</dd>
113 * </dl>
115 * <p><b>Note:</b> the layer numbering order is the <em>reverse</em> of the
116 * component indexing and position order</p>
118 * @author Graydon Hoare (graydon@redhat.com)
119 * @author Roman Kennke (kennke@aicas.com)
121 public class JLayeredPane extends JComponent implements Accessible
125 * Provides accessibility support for <code>JLayeredPane</code>.
127 protected class AccessibleJLayeredPane extends AccessibleJComponent
130 * Creates a new instance of <code>AccessibleJLayeredPane</code>.
132 protected AccessibleJLayeredPane()
134 // Nothing to do here.
138 * Returns the accessble role of <code>JLayeredPane</code>,
139 * {@link AccessibleRole#LAYERED_PANE}.
141 public AccessibleRole getAccessibleRole()
143 return AccessibleRole.LAYERED_PANE;
147 private static final long serialVersionUID = 5534920399324590459L;
149 public static final String LAYER_PROPERTY = "layeredContainerLayer";
151 public static final Integer FRAME_CONTENT_LAYER = new Integer(-30000);
153 public static final Integer DEFAULT_LAYER = new Integer(0);
154 public static final Integer PALETTE_LAYER = new Integer(100);
155 public static final Integer MODAL_LAYER = new Integer(200);
156 public static final Integer POPUP_LAYER = new Integer(300);
157 public static final Integer DRAG_LAYER = new Integer(400);
159 private Hashtable componentToLayer; // Component -> Layer Number (Integer)
161 public JLayeredPane()
163 componentToLayer = new Hashtable();
164 setLayout(null);
167 /**
168 * Looks up the layer a child component is currently assigned to.
170 * If <code>c</code> is an instance of {@link JComponent}, then the layer
171 * is fetched from the client property with the key {@link #LAYER_PROPERTY}.
172 * Otherwise it is looked up in an internal hashtable that maps
173 * non-JComponent components to layers. If the components cannot be found
174 * in either way, the {@link #DEFAULT_LAYER} is returned.
176 * @param c the component to look up.
178 * @return the layer the component is currently assigned to; if the component
179 * is not in this layered pane, then 0 (DEFAULT_LAYER) is returned
181 public int getLayer(Component c)
183 Integer layerObj;
184 if (c instanceof JComponent)
186 JComponent jc = (JComponent) c;
187 layerObj = (Integer) jc.getClientProperty(LAYER_PROPERTY);
189 else
190 layerObj = (Integer) componentToLayer.get(c);
192 if (layerObj == null)
193 layerObj = DEFAULT_LAYER;
195 return layerObj.intValue();
199 * Looks up the layer in the client property with the key
200 * {@link #LAYER_PROPERTY} of <code>comp</code>. If no such property can be
201 * found, we return <code>0</code> ({@link #DEFAULT_LAYER}).
203 * @param comp the component for which the layer is looked up
205 * @return the layer of <code>comp</code> as stored in the corresponding
206 * client property, or <code>0</code> if there is no such property
208 public static int getLayer(JComponent comp)
210 Integer layerObj = (Integer) comp.getClientProperty(LAYER_PROPERTY);
211 if (layerObj == null)
212 layerObj = DEFAULT_LAYER;
213 return layerObj.intValue();
217 * Returns the first JLayeredPane that contains the Component
218 * <code>comp</code> or <code>null</code> if <code>comp</code> is
219 * not contained in a JLayeredPane.
221 * @param comp the component for which we are searching the JLayeredPane
222 * ancestor
224 * @return the first JLayeredPane that contains the Component
225 * <code>comp</code> or <code>null</code> if <code>comp</code> is
226 * not contained in a JLayeredPane
228 public static JLayeredPane getLayeredPaneAbove(Component comp)
230 JLayeredPane lp = (JLayeredPane) SwingUtilities.getAncestorOfClass
231 (JLayeredPane.class, comp);
232 return lp;
236 * Return the greatest layer number currently in use, in this container.
237 * This number may legally be positive <em>or</em> negative.
239 * @return the highest layer number
241 * @see #lowestLayer()
243 public int highestLayer()
245 Component[] components = getComponents();
246 int highest;
247 if (components.length == 0)
248 highest = 0;
249 else
251 highest = Integer.MIN_VALUE;
252 for (int i = 0; i < components.length; i++)
253 highest = Math.max(highest, getLayer(components[i]));
255 return highest;
259 * Return the least layer number currently in use, in this container.
260 * This number may legally be positive <em>or</em> negative.
262 * @return the least layer number
264 * @see #highestLayer()
266 public int lowestLayer()
268 Component[] components = getComponents();
269 int lowest;
270 if (components.length == 0)
271 lowest = 0;
272 else
274 lowest = Integer.MAX_VALUE;
275 for (int i = 0; i < components.length; i++)
276 lowest = Math.max(lowest, getLayer(components[i]));
278 return lowest;
282 * Moves a component to the "front" of its layer. The "front" is a
283 * synonym for position 0, which is also the last position drawn in each
284 * layer, so is usually the component which occludes the most other
285 * components in its layer.
287 * @param c the component to move to the front of its layer
289 * @see #moveToBack
291 public void moveToFront(Component c)
293 setPosition (c, 0);
297 * <p>Moves a component to the "back" of its layer. The "back" is a
298 * synonym for position N-1 (also known as position -1), where N is the
299 * size of the layer.</p>
301 * <p>The "back" of a layer is the first position drawn, so the component at
302 * the "back" is usually the component which is occluded by the most
303 * other components in its layer.</p>
305 * @param c the component to move to the back of its layer.
307 * @see #moveToFront
309 public void moveToBack(Component c)
311 setPosition (c, -1);
315 * Return the position of a component within its layer. Positions are assigned
316 * from the "front" (position 0) to the "back" (position N-1), and drawn from
317 * the back towards the front.
319 * @param c the component to get the position of
321 * @return the position of <code>c</code> within its layer or -1 if
322 * <code>c</code> is not a child of this layered pane
324 * @see #setPosition
326 public int getPosition(Component c)
328 int pos = -1;
329 int index = getIndexOf(c);
330 if (index >= 0)
332 pos = 0;
333 int layer = getLayer(c);
334 for (int i = index - 1; i >= 0; --i)
336 if (layer == getLayer(getComponent(i)))
337 pos++;
338 else
339 break;
342 return pos;
346 * Change the position of a component within its layer. Positions are assigned
347 * from the "front" (position 0) to the "back" (position N-1), and drawn from
348 * the back towards the front.
350 * @param c the component to change the position of
351 * @param position the position to assign the component to
353 * @see #getPosition
355 public void setPosition(Component c, int position)
357 setLayer(c, getLayer(c), position);
361 * Return an array of all components within a layer of this
362 * container. Components are ordered front-to-back, with the "front"
363 * element (which draws last) at position 0 of the returned array.
365 * @param layer the layer to return components from
367 * @return the components in the layer
369 public Component[] getComponentsInLayer(int layer)
371 Component[] inLayer = new Component[getComponentCountInLayer(layer)];
372 Component[] components = getComponents();
373 int j = 0;
374 for (int i = 0; i < components.length; ++i)
376 if (layer == getLayer(components[i]))
378 inLayer[j] = components[i];
379 j++;
382 return inLayer;
386 * Return the number of components within a layer of this
387 * container.
389 * @param layer the layer count components in
391 * @return the number of components in the layer
393 public int getComponentCountInLayer(int layer)
395 Component[] components = getComponents();
396 int count = 0;
397 for (int i = components.length - 1; i >= 0; --i)
399 if (getLayer(components[i]) == layer)
400 count++;
402 return count;
406 * Return a hashtable mapping child components of this container to
407 * Integer objects representing the component's layer assignments.
409 protected Hashtable<Component, Integer> getComponentToLayer()
411 return componentToLayer;
415 * Return the index of a component within the underlying (contiguous)
416 * array of children. This is a "raw" number which does not represent the
417 * child's position in a layer, but rather its position in the logical
418 * drawing order of all children of the container.
420 * @param c the component to look up.
422 * @return the external index of the component or <code>-1</code> if
423 * <code>c</code> is not a child of this layered pane
425 public int getIndexOf(Component c)
427 return getComponentZOrder(c);
431 * Return an Integer object which holds the same int value as the
432 * parameter. This is strictly an optimization to minimize the number of
433 * identical Integer objects which we allocate.
435 * @param layer the layer number as an int.
437 * @return the layer number as an Integer, possibly shared.
439 protected Integer getObjectForLayer(int layer)
441 switch (layer)
443 case -30000:
444 return FRAME_CONTENT_LAYER;
446 case 0:
447 return DEFAULT_LAYER;
449 case 100:
450 return PALETTE_LAYER;
452 case 200:
453 return MODAL_LAYER;
455 case 300:
456 return POPUP_LAYER;
458 case 400:
459 return DRAG_LAYER;
461 default:
462 break;
465 return new Integer(layer);
469 * Computes an index at which to request the superclass {@link
470 * java.awt.Container} inserts a component, given an abstract layer and
471 * position number.
473 * @param layer the layer in which to insert a component.
474 * @param position the position in the layer at which to insert a component.
476 * @return the index at which to insert the component.
478 protected int insertIndexForLayer(int layer, int position)
480 return insertIndexForLayer(null, layer, position);
484 * Similar to {@link #insertIndexForLayer(int, int)}, only that it takes a
485 * component parameter, which should be ignored in the search. This is
486 * necessary to support {@link #setLayer(Component, int, int)} which uses
487 * Container.setComponentZOrder(), which doesn't remove the component.
489 * @param comp the component to ignore
490 * @param layer the layer
491 * @param position the position
493 * @return the insertion index
495 private int insertIndexForLayer(Component comp, int layer, int position)
497 // Create the component list to search through.
498 ArrayList l = new ArrayList();
499 int count = getComponentCount();
500 for (int i = 0; i < count; i++)
502 Component c = getComponent(i);
503 if (c != comp)
504 l.add(c);
507 count = l.size();
508 int layerStart = -1;
509 int layerEnd = -1;
510 for (int i = 0; i < count; i++)
512 int layerOfComponent = getLayer((Component) l.get(i));
513 if (layerStart == -1 && layerOfComponent == layer)
514 layerStart = i;
515 if (layerOfComponent < layer)
517 // We are beyond the layer that we are looking for. Update the
518 // layerStart and layerEnd and exit the loop.
519 if (i == 0)
521 layerStart = 0;
522 layerEnd = 0;
524 else
525 layerEnd = i;
526 break;
530 // No layer found. The requested layer is lower than any existing layer,
531 // put the component at the end.
532 int insertIndex;
533 if (layerStart == -1 && layerEnd == -1)
535 insertIndex = count;
537 else
539 // Corner cases.
540 if (layerStart != -1 && layerEnd == -1)
541 layerEnd = count;
542 if (layerStart == -1 && layerEnd != -1)
543 layerStart = layerEnd;
545 // Adding to the bottom of a layer returns the end index
546 // in the layer.
547 if (position == -1)
548 insertIndex = layerEnd;
549 else
551 // Insert into a layer.
552 if (position > -1 && layerStart + position <= layerEnd)
553 insertIndex = layerStart + position;
554 else
555 insertIndex = layerEnd;
558 return insertIndex;
562 * Removes a child from this container. The child is specified by
563 * index. After removal, the child no longer occupies a layer.
565 * @param index the index of the child component to remove.
567 public void remove(int index)
569 Component c = getComponent(index);
570 if (! (c instanceof JComponent))
571 componentToLayer.remove(c);
572 super.remove(index);
576 * Removes all components from this container.
578 * @since 1.5
580 public void removeAll()
582 componentToLayer.clear();
583 super.removeAll();
587 * <p>Set the layer property for a component, within this container. The
588 * component will be implicitly mapped to the bottom-most position in the
589 * layer, but only if added <em>after</em> calling this method.</p>
591 * <p>Read that carefully: this method should be called <em>before</em> the
592 * component is added to the container.</p>
594 * @param c the component to set the layer property for.
595 * @param layer the layer number to assign to the component.
597 public void setLayer(Component c, int layer)
599 setLayer(c, layer, -1);
603 * Set the layer and position of a component, within this container.
605 * @param c the child component to set the layer property for.
606 * @param layer the layer number to assign to the component.
607 * @param position the position number to assign to the component.
609 public void setLayer(Component c, int layer, int position)
611 Integer layerObj = getObjectForLayer(layer);
613 // Nothing to do if neither the layer nor the position is
614 // changed.
615 if (layer != getLayer(c) || position != getPosition(c))
617 // Store the layer either in the JComponent or in the hashtable
618 if (c instanceof JComponent)
620 JComponent jc = (JComponent) c;
621 jc.putClientProperty(LAYER_PROPERTY, layerObj);
623 else
624 componentToLayer.put (c, layerObj);
626 // Update the component in the Z order of the Container.
627 Container parent = c.getParent();
628 if (parent == this)
630 int index = insertIndexForLayer(c, layer, position);
631 setComponentZOrder(c, index);
634 repaint(c.getX(), c.getY(), c.getWidth(), c.getHeight());
638 * Overrides the default implementation from {@link java.awt.Container}
639 * such that <code>layerConstraint</code> is interpreted as an {@link
640 * Integer}, specifying the layer to which the component will be added
641 * (at the bottom position).
643 * The argument <code>index</code> specifies the position within the layer
644 * at which the component should be added, where <code>0</code> is the top
645 * position greater values specify positions below that and <code>-1</code>
646 * specifies the bottom position.
648 * @param comp the component to add
649 * @param layerConstraint an integer specifying the layer to add the
650 * component to
651 * @param index the position within the layer
653 protected void addImpl(Component comp, Object layerConstraint, int index)
655 int layer;
656 if (layerConstraint != null && layerConstraint instanceof Integer)
658 layer = ((Integer) layerConstraint).intValue();
659 setLayer(comp, layer);
661 else
662 layer = getLayer(comp);
664 int newIdx = insertIndexForLayer(layer, index);
665 super.addImpl(comp, layerConstraint, newIdx);
666 comp.validate();
667 comp.repaint();
671 * Sets the layer property for a JComponent.
673 * @param component the component for which to set the layer
674 * @param layer the layer property to set
676 public static void putLayer(JComponent component, int layer)
678 component.putClientProperty(LAYER_PROPERTY, new Integer(layer));
682 * Returns the accessible context for this <code>JLayeredPane</code>.
684 * @return the accessible context for this <code>JLayeredPane</code>
686 public AccessibleContext getAccessibleContext()
688 if (accessibleContext == null)
689 accessibleContext = new AccessibleJLayeredPane();
690 return accessibleContext;
694 * This method is overridden order to provide a reasonable painting
695 * mechanism for <code>JLayeredPane</code>. This is necessary since
696 * <code>JLayeredPane</code>'s do not have an own UI delegate.
698 * Basically this method clears the background for the
699 * <code>JLayeredPane</code> and then calls <code>super.paint(g)</code>.
701 * @param g the graphics context to use
703 public void paint(Graphics g)
705 if (isOpaque())
707 Color oldColor = g.getColor();
708 Rectangle clip = g.getClipBounds();
709 g.setColor(getBackground());
710 g.fillRect(clip.x, clip.y, clip.width, clip.height);
711 g.setColor(oldColor);
713 super.paint(g);
717 * Returns <code>false</code> if components in this layered pane can overlap,
718 * otherwise <code>true</code>.
720 * @return <code>false</code> if components in this layered pane can overlap,
721 * otherwise <code>true</code>
723 public boolean isOptimizedDrawingEnabled()
725 int numChildren = getComponentCount();
726 boolean result = true;
727 for (int i = 0; i < numChildren; ++i)
729 Component c1 = getComponent(i);
730 if (! c1.isVisible())
731 continue;
732 Rectangle r1 = c1.getBounds();
733 if (r1.isEmpty())
734 continue;
736 for (int j = i + 1; j < numChildren; ++j)
738 Component c2 = getComponent(j);
739 if (! c2.isVisible())
740 continue;
741 Rectangle r2 = c2.getBounds();
742 if (r2.isEmpty())
743 continue;
744 if (r1.intersects(r2))
746 result = false;
747 break;
749 if (result == false)
750 break;
753 return result;