Merge from the pain train
[official-gcc.git] / libjava / javax / swing / JLayeredPane.java
blobcdafd8b869f478b39f79fe82481c272cdf82413e
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., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 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.Component;
42 import java.util.Hashtable;
43 import java.util.Iterator;
44 import java.util.Map;
45 import java.util.TreeMap;
47 import javax.accessibility.Accessible;
49 /**
50 * <p>The "Layered Pane" is a container which divides its children into 6 (or
51 * more) disjoint sets. the pre-defined sets are:</p>
53 * <ul>
54 * <li>"Frame Content"</li>
55 * <li>"Default"</li>
56 * <li>"Palette"</li>
57 * <li>"Modal"</li>
58 * <li>"Popup"</li>
59 * <li>"Drag"</li>
60 * </ul>
62 * <p>A child is in exactly one of these layers at any time, though there may
63 * be other layers if someone creates them.</p>
65 * <p>The purpose of this class is to translate this view of "layers" into a
66 * contiguous array of components: the one held in our ancestor,
67 * {@link java.awt.Container}.</p>
69 * <p>There is a precise set of words we will use to refer to numbers within
70 * this class:</p>
72 * <dl>
73 * <dt>Component Index:</dt>
74 * <dd>An offset into the <code>component</code> array held in our ancestor,
75 * {@link java.awt.Container}, from <code>[0 .. component.length)</code>. The drawing
76 * rule with indices is that 0 is drawn last.</dd>
78 * <dt>Layer Number:</dt>
79 * <dd>A general <code>int</code> specifying a layer within this component. Negative
80 * numbers are drawn first, then layer 0, then positive numbered layers, in
81 * ascending order.</dd>
83 * <dt>Position:</dt>
84 * <dd>An offset into a layer's "logical drawing order". Layer position 0
85 * is drawn last. Layer position -1 is a synonym for the first layer
86 * position (the logical "bottom").</dd>
87 * </dl>
89 * <p><b>Note:</b> the layer numbering order is the <em>reverse</em> of the
90 * component indexing and position order</p>
92 * @author Graydon Hoare (graydon@redhat.com)
94 public class JLayeredPane extends JComponent implements Accessible
96 private static final long serialVersionUID = 5534920399324590459L;
98 public static final String LAYER_PROPERTY = "layeredContainerLayer";
100 public static Integer FRAME_CONTENT_LAYER = new Integer (-30000);
102 public static Integer DEFAULT_LAYER = new Integer (0);
103 public static Integer PALETTE_LAYER = new Integer (100);
104 public static Integer MODAL_LAYER = new Integer (200);
105 public static Integer POPUP_LAYER = new Integer (300);
106 public static Integer DRAG_LAYER = new Integer (400);
108 TreeMap layers; // Layer Number (Integer) -> Layer Size (Integer)
109 Hashtable componentToLayer; // Component -> Layer Number (Integer)
111 public JLayeredPane()
113 layers = new TreeMap ();
114 componentToLayer = new Hashtable ();
118 /**
119 * Looks up the layer a child component is currently assigned to.
121 * @param c the component to look up.
122 * @return the layer the component is currently assigned to, in this container.
123 * @throws IllegalArgumentException if the component is not a child of this container.
125 public int getLayer(Component c)
127 if (! componentToLayer.containsKey (c))
128 throw new IllegalArgumentException ();
129 return ((Integer) componentToLayer.get(c)).intValue();
133 * <p>Returns a pair of ints representing a half-open interval
134 * <code>[top, bottom)</code>, which is the range of component indices
135 * the provided layer number corresponds to.</p>
137 * <p>Note that "bottom" is <em>not</em> included in the interval of
138 * component indices in this layer: a layer with 0 elements in it has
139 * <code>ret[0] == ret[1]</code>.</p>
141 * @param layer the layer to look up.
142 * @return the half-open range of indices this layer spans.
143 * @throws IllegalArgumentException if layer does not refer to an active layer
144 * in this container.
146 private int[] layerToRange (Integer layer)
148 int[] ret = new int[2];
149 ret[1] = getComponents ().length;
150 Iterator i = layers.entrySet ().iterator ();
151 while (i.hasNext())
153 Map.Entry pair = (Map.Entry) i.next();
154 Integer layerNum = (Integer) pair.getKey ();
155 Integer layerSz = (Integer) pair.getValue ();
156 if (layerNum.intValue() == layer.intValue())
158 ret[0] = ret[1] - layerSz.intValue ();
159 return ret;
161 else
163 ret[1] -= layerSz.intValue ();
166 // should have found the layer during iteration
167 throw new IllegalArgumentException ();
171 * Increments the recorded size of a given layer.
173 * @param layer the layer number to increment.
174 * @see #incrLayer()
176 private void incrLayer(Integer layer)
178 int sz = 1;
179 if (layers.containsKey (layer))
180 sz += ((Integer)(layers.get (layer))).intValue ();
181 layers.put (layer, new Integer(sz));
185 * Decrements the recorded size of a given layer.
187 * @param layer the layer number to decrement.
188 * @see #decrLayer()
190 private void decrLayer(Integer layer)
192 int sz = 0;
193 if (layers.containsKey (layer))
194 sz = ((Integer)(layers.get (layer))).intValue () - 1;
195 layers.put (layer, new Integer(sz));
199 * Return the greatest layer number currently in use, in this container.
200 * This number may legally be positive <em>or</em> negative.
202 * @return the least layer number.
203 * @see #lowestLayer()
205 public int highestLayer()
207 if (layers.size() == 0)
208 return 0;
209 return ((Integer)(layers.lastKey ())).intValue ();
213 * Return the least layer number currently in use, in this container.
214 * This number may legally be positive <em>or</em> negative.
216 * @return the least layer number.
217 * @see #highestLayer()
219 public int lowestLayer()
221 if (layers.size() == 0)
222 return 0;
223 return ((Integer)(layers.firstKey ())).intValue ();
227 * Moves a component to the "front" of its layer. The "front" is a
228 * synonym for position 0, which is also the last position drawn in each
229 * layer, so is usually the component which occludes the most other
230 * components in its layer.
232 * @param c the component to move to the front of its layer.
233 * @throws IllegalArgumentException if the component is not a child of
234 * this container.
235 * @see #moveToBack()
237 public void moveToFront(Component c)
239 setPosition (c, 0);
243 * <p>Moves a component to the "back" of its layer. The "back" is a
244 * synonym for position N-1 (also known as position -1), where N is the
245 * size of the layer.</p>
247 * <p>The "back" of a layer is the first position drawn, so the component at
248 * the "back" is usually the component which is occluded by the most
249 * other components in its layer.</p>
251 * @param c the component to move to the back of its layer.
252 * @throws IllegalArgumentException if the component is not a child of
253 * this container.
254 * @see #moveToFront()
256 public void moveToBack(Component c)
258 setPosition (c, -1);
262 * Return the position of a component within its layer. Positions are assigned
263 * from the "front" (position 0) to the "back" (position N-1), and drawn from
264 * the back towards the front.
266 * @param c the component to get the position of.
267 * @throws IllegalArgumentException if the component is not a child of
268 * this container.
269 * @see #setPosition()
271 public int getPosition(Component c)
273 int layer = getLayer (c);
274 int[] range = layerToRange(new Integer(layer));
275 int top = range[0];
276 int bot = range[1];
277 Component[] comps = getComponents ();
278 for (int i = top; i < bot; ++i)
280 if (comps[i] == c)
281 return i - top;
283 // should have found it
284 throw new IllegalArgumentException ();
288 * Change the position of a component within its layer. Positions are assigned
289 * from the "front" (position 0) to the "back" (position N-1), and drawn from
290 * the back towards the front.
292 * @param c the component to change the position of.
293 * @param position the position to assign the component to.
294 * @throws IllegalArgumentException if the component is not a child of
295 * this container.
296 * @see #getPosition()
298 public void setPosition(Component c, int position)
300 int layer = getLayer (c);
301 int[] range = layerToRange(new Integer(layer));
302 if (range[0] == range[1])
303 throw new IllegalArgumentException ();
305 int top = range[0];
306 int bot = range[1];
307 if (position == -1)
308 position = (bot - top) - 1;
309 int targ = Math.min(top + position, bot-1);
310 int curr = -1;
312 Component[] comps = getComponents();
313 for (int i = top; i < bot; ++i)
315 if (comps[i] == c)
317 curr = i;
318 break;
321 if (curr == -1)
322 // should have found it
323 throw new IllegalArgumentException();
325 super.swapComponents (curr, targ);
326 revalidate();
327 repaint();
331 * Return an array of all components within a layer of this
332 * container. Components are ordered front-to-back, with the "front"
333 * element (which draws last) at position 0 of the returned array.
335 * @param layer the layer to return components from.
336 * @return the components in the layer.
338 public Component[] getComponentsInLayer(int layer)
340 int[] range = layerToRange (getObjectForLayer (layer));
341 if (range[0] == range[1])
342 return new Component[0];
343 else
345 Component[] comps = getComponents ();
346 int sz = range[1] - range[0];
347 Component[] nc = new Component[sz];
348 for (int i = 0; i < sz; ++i)
349 nc[i] = comps[range[0] + i];
350 return nc;
355 * Return the number of components within a layer of this
356 * container.
358 * @param layer the layer count components in.
359 * @return the number of components in the layer.
361 public int getComponentCountInLayer(int layer)
363 int[] range = layerToRange (getObjectForLayer (layer));
364 if (range[0] == range[1])
365 return 0;
366 else
367 return (range[1] - range[0]);
371 * Return a hashtable mapping child components of this container to
372 * Integer objects representing the component's layer assignments.
374 protected Hashtable getComponentToLayer()
376 return componentToLayer;
380 * Return the index of a component within the underlying (contiguous)
381 * array of children. This is a "raw" number which does not represent the
382 * child's position in a layer, but rather its position in the logical
383 * drawing order of all children of the container.
385 * @param c the component to look up.
386 * @return the external index of the component.
387 * @throws IllegalArgumentException if the component is not a child of
388 * this container.
390 public int getIndexOf(Component c)
392 int layer = getLayer (c);
393 int[] range = layerToRange(new Integer(layer));
394 Component[] comps = getComponents();
395 for (int i = range[0]; i < range[1]; ++i)
397 if (comps[i] == c)
398 return i;
400 // should have found the component during iteration
401 throw new IllegalArgumentException ();
405 * Return an Integer object which holds the same int value as the
406 * parameter. This is strictly an optimization to minimize the number of
407 * identical Integer objects which we allocate.
409 * @param layer the layer number as an int.
410 * @return the layer number as an Integer, possibly shared.
412 protected Integer getObjectForLayer(int layer)
414 switch (layer)
416 case -30000:
417 return FRAME_CONTENT_LAYER;
419 case 0:
420 return DEFAULT_LAYER;
422 case 100:
423 return PALETTE_LAYER;
425 case 200:
426 return MODAL_LAYER;
428 case 300:
429 return POPUP_LAYER;
431 case 400:
432 return DRAG_LAYER;
434 default:
435 break;
438 return new Integer(layer);
442 * Computes an index at which to request the superclass {@link
443 * java.awt.Container} inserts a component, given an abstract layer and
444 * position number.
446 * @param layer the layer in which to insert a component.
447 * @param position the position in the layer at which to insert a component.
448 * @return the index at which to insert the component.
450 protected int insertIndexForLayer(int layer, int position)
453 Integer lobj = getObjectForLayer (layer);
454 if (! layers.containsKey(lobj))
455 layers.put (lobj, new Integer (0));
456 int[] range = layerToRange (lobj);
457 if (range[0] == range[1])
458 return range[0];
460 int top = range[0];
461 int bot = range[1];
463 if (position == -1 || position > (bot - top))
464 return bot;
465 else
466 return top + position;
470 * Removes a child from this container. The child is specified by
471 * index. After removal, the child no longer occupies a layer.
473 * @param index the index of the child component to remove.
475 public void remove (int index)
477 Component c = getComponent (index);
478 int layer = getLayer (c);
479 decrLayer (new Integer(layer));
480 componentToLayer.remove (c);
481 super.remove (index);
482 revalidate();
483 repaint();
487 * Removes a child from this container. The child is specified directly.
488 * After removal, the child no longer occupies a layer.
490 * @param comp the child to remove.
492 public void remove (Component comp)
494 remove (getIndexOf (comp));
498 * <p>Set the layer property for a component, within this container. The
499 * component will be implicitly mapped to the bottom-most position in the
500 * layer, but only if added <em>after</em> calling this method.</p>
502 * <p>Read that carefully: this method should be called <em>before</em> the
503 * component is added to the container.</p>
505 * @param c the component to set the layer property for.
506 * @param layer the layer number to assign to the component.
508 public void setLayer(Component c, int layer)
510 componentToLayer.put (c, getObjectForLayer (layer));
514 * Set the layer and position of a component, within this container.
516 * @param c the child component to set the layer property for.
517 * @param layer the layer number to assign to the component.
518 * @param position the position number to assign to the component.
520 public void setLayer(Component c,
521 int layer,
522 int position)
524 remove(c);
525 add(c, getObjectForLayer (layer));
526 setPosition(c, position);
527 revalidate();
528 repaint();
532 * Overrides the default implementation from {@link java.awt.Container}
533 * such that <code>layerConstraint</code> is interpreted as an {@link
534 * Integer}, specifying the layer to which the component will be added
535 * (at the bottom position).
537 * @param comp the component to add.
538 * @param layerConstraint an integer specifying the layer to add the component to.
539 * @param index an ignored parameter, for compatibility.
541 protected void addImpl(Component comp, Object layerConstraint, int index)
543 Integer layer;
544 if (layerConstraint != null && layerConstraint instanceof Integer)
545 layer = (Integer) layerConstraint;
546 else if (componentToLayer.containsKey (comp))
547 layer = (Integer) componentToLayer.remove (comp);
548 else
549 layer = DEFAULT_LAYER;
551 int newIdx = insertIndexForLayer(layer.intValue (), index);
553 componentToLayer.put (comp, layer);
554 incrLayer (layer);
556 super.addImpl(comp, null, newIdx);
557 revalidate();
558 repaint();