001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package javax.swing;
018:
019: import java.awt.Color;
020: import java.awt.Component;
021: import java.awt.Graphics;
022: import java.util.Hashtable;
023: import javax.accessibility.Accessible;
024: import javax.accessibility.AccessibleContext;
025: import javax.accessibility.AccessibleRole;
026:
027: /**
028: * <p>
029: * <i>JLabel</i> implements a container with support for layers.
030: * </p>
031: * <h3>Implementation Notes:</h3>
032: * <ul>
033: * <li>The <code>serialVersionUID</code> fields are explicitly declared as a performance
034: * optimization, not as a guarantee of serialization compatibility.</li>
035: * </ul>
036: */
037: public class JLayeredPane extends JComponent implements Accessible {
038: private static final long serialVersionUID = -2657754894035116214L;
039:
040: private static final int DELAULT_LAYER_NUMBER = 0;
041:
042: private static final int PALETTE_LAYER_NUMBER = 100;
043:
044: private static final int MODAL_LAYER_NUMBER = 200;
045:
046: private static final int POPUP_LAYER_NUMBER = 300;
047:
048: private static final int DRAG_LAYER_NUMBER = 400;
049:
050: private static final int FRAME_CONTENT_LAYER_NUMBER = -30000;
051:
052: public static final Integer DEFAULT_LAYER;
053:
054: public static final Integer PALETTE_LAYER;
055:
056: public static final Integer MODAL_LAYER;
057:
058: public static final Integer POPUP_LAYER;
059:
060: public static final Integer DRAG_LAYER;
061:
062: public static final Integer FRAME_CONTENT_LAYER;
063:
064: public static final String LAYER_PROPERTY = "layeredContainerLayer";
065: static {
066: DEFAULT_LAYER = new Integer(DELAULT_LAYER_NUMBER);
067: PALETTE_LAYER = new Integer(PALETTE_LAYER_NUMBER);
068: MODAL_LAYER = new Integer(MODAL_LAYER_NUMBER);
069: POPUP_LAYER = new Integer(POPUP_LAYER_NUMBER);
070: DRAG_LAYER = new Integer(DRAG_LAYER_NUMBER);
071: FRAME_CONTENT_LAYER = new Integer(FRAME_CONTENT_LAYER_NUMBER);
072: }
073:
074: /**
075: * Implements accessibility support for <code>JLayeredPane</code>
076: */
077: protected class AccessibleJLayeredPane extends AccessibleJComponent {
078: private static final long serialVersionUID = 3492700363505144784L;
079:
080: /**
081: * Constructs new <code>AccessibleJLayeredPane</code>.
082: */
083: protected AccessibleJLayeredPane() {
084: super ();
085: }
086:
087: /**
088: * Returns the accessible role of the object.
089: *
090: * @return <code>AccessibleRole</code> that describes the accessible
091: * role of the object
092: */
093: @Override
094: public AccessibleRole getAccessibleRole() {
095: return AccessibleRole.LAYERED_PANE;
096: }
097: }
098:
099: /**
100: * The hash table used to store layers for components.
101: */
102: private Hashtable<Component, Integer> componentToLayer;
103:
104: /**
105: * Constructs new <code>JLayeredPane</code>
106: */
107: public JLayeredPane() {
108: super ();
109: }
110:
111: /**
112: * Adds the specified component to the container using the specified
113: * index and the specified constraints.
114: *
115: * @param comp component to add
116: * @param constraints constraints to be applied (layer)
117: * @param index position of the component in the layer, where
118: * -1 means the bottommost position and 0 means the topmost position
119: */
120: @Override
121: protected void addImpl(final Component comp,
122: final Object constraints, final int index) {
123: super .remove(comp);
124: int layer = DELAULT_LAYER_NUMBER;
125: Object newConstraints = constraints;
126: if (constraints == null) {
127: layer = getLayer(comp);
128: } else if (constraints instanceof Integer) {
129: layer = ((Integer) constraints).intValue();
130: newConstraints = null;
131: rememberLayerForComponent(comp, layer);
132: }
133: super .addImpl(comp, newConstraints, insertIndexForLayer(layer,
134: index));
135: /*
136: * Unlike other containers, JLayeredPane has to validate added
137: * components immediatelly (this is used, for example, in tool tips
138: * implementation)
139: */
140: comp.validate();
141: }
142:
143: /**
144: * Returns <code>AccessibleContext</code> for <code>JLayeredPane</code>.
145: *
146: * @return <code>AccessibleContext</code> associated with this layered pane
147: */
148: @Override
149: public AccessibleContext getAccessibleContext() {
150: if (accessibleContext == null) {
151: accessibleContext = new AccessibleJLayeredPane();
152: }
153: return accessibleContext;
154: }
155:
156: /**
157: * Returns the hash table that maps components to layers.
158: *
159: * @return the hash table that maps components to layers
160: */
161: //XXX: 1.5 migration: uncomment
162: //protected Hashtable<Component,Integer> getComponentToLayer()
163: protected Hashtable<java.awt.Component, java.lang.Integer> getComponentToLayer() {
164: if (componentToLayer == null) {
165: componentToLayer = new Hashtable<java.awt.Component, java.lang.Integer>();
166: }
167: return componentToLayer;
168: }
169:
170: /**
171: * Returns string representation of this layered pane.
172: *
173: * @return string representation of this layered pane
174: */
175: @Override
176: protected String paramString() {
177: return super .paramString();
178: }
179:
180: /**
181: * Returns the object that represents the specified layer.
182: *
183: * @param layer the specified layer
184: *
185: * @return the object that represents the specified layer
186: */
187: protected Integer getObjectForLayer(final int layer) {
188: // TODO: replace with Integer.valueOf(layer) after migrating to 1.5
189: switch (layer) {
190: case DELAULT_LAYER_NUMBER:
191: return DEFAULT_LAYER;
192: case PALETTE_LAYER_NUMBER:
193: return PALETTE_LAYER;
194: case MODAL_LAYER_NUMBER:
195: return MODAL_LAYER;
196: case POPUP_LAYER_NUMBER:
197: return POPUP_LAYER;
198: case DRAG_LAYER_NUMBER:
199: return DRAG_LAYER;
200: case FRAME_CONTENT_LAYER_NUMBER:
201: return FRAME_CONTENT_LAYER;
202: }
203: return new Integer(layer);
204: }
205:
206: /**
207: * Paints the layered pane within the specified graphic context.
208: *
209: * @param g the graphic context
210: */
211: @Override
212: public void paint(final Graphics g) {
213: // JLayeredPane doesn't have UI,
214: // it has to paint its background by itself
215: if (ui == null && isOpaque()) {
216: // paint background
217: Color savedColor = g.getColor();
218: g.setColor(getBackground());
219: g.fillRect(0, 0, getWidth(), getHeight());
220: g.setColor(savedColor);
221: }
222: super .paint(g);
223: }
224:
225: /**
226: * Sets the layer and the position for the specified component.
227: *
228: * @param c the component to set layer to
229: * @param layer the layer to set
230: * @param position the position to set, 0 means the topmost position and
231: * -1 means the bottommost position
232: */
233: public void setLayer(final Component c, final int layer,
234: final int position) {
235: int index = getIndexOf(c);
236: if (index == -1
237: || index == insertIndexForLayer(layer, position)) {
238: rememberLayerForComponent(c, layer);
239: return;
240: }
241: addImpl(c, getObjectForLayer(layer), position);
242: }
243:
244: /**
245: * Sets the layer for the specified component.
246: *
247: * @param c the component to set layer to
248: * @param layer the layer to set
249: */
250: public void setLayer(final Component c, final int layer) {
251: setLayer(c, layer, -1);
252: }
253:
254: /**
255: * Sets the position of the component inside its layer.
256: * 0 means the topmost position and -1 means the bottommost position.
257: *
258: * @param c the component to move
259: * @param position the position to set
260: */
261: public void setPosition(final Component c, final int position) {
262: int layer = getLayer(c);
263: int index = getIndexOf(c);
264: if (index == -1) {
265: // do nothing if c is not in the container
266: return;
267: }
268: setLayer(c, layer, position);
269: }
270:
271: /**
272: * Moves the component to the top of its layer (position 0);
273: *
274: * @param c the component to move
275: */
276: public void moveToFront(final Component c) {
277: setPosition(c, 0);
278: }
279:
280: /**
281: * Moves the component to the bottom of its layer (position -1);
282: *
283: * @param c the component to move
284: */
285: public void moveToBack(final Component c) {
286: setPosition(c, -1);
287: }
288:
289: /**
290: *
291: * @param c
292: *
293: * @return position of component c in its layer
294: * -1 if c is not in the containter
295: */
296: public int getPosition(final Component c) {
297: int index = getIndexOf(c);
298: int layer = getLayer(c);
299: int pos = -1;
300: for (; index >= 0 && getLayer(getComponent(index)) == layer; index--) {
301: pos++;
302: }
303: return pos;
304: }
305:
306: /**
307: *
308: * @param c
309: *
310: * @return layer of component c
311: */
312: public int getLayer(final Component c) {
313: Object layer = getComponentToLayer().get(c);
314: if (layer != null) {
315: return ((Integer) layer).intValue();
316: }
317: if (c instanceof JComponent) {
318: return getLayer((JComponent) c);
319: }
320: return 0;
321: }
322:
323: public int getIndexOf(final Component c) {
324: return getComponentZOrder(c);
325: }
326:
327: public Component[] getComponentsInLayer(final int layer) {
328: int size = getComponentCountInLayer(layer);
329: Component[] result = new Component[size];
330: if (size == 0) {
331: return result;
332: }
333: int i = insertIndexForLayer(layer, 0);
334: int j = 0;
335: for (; i < getComponentCount()
336: && layer == getLayer(getComponent(i)); i++, j++) {
337: result[j] = getComponent(i);
338: }
339: return result;
340: }
341:
342: protected int insertIndexForLayer(final int layer,
343: final int position) {
344: return insertIndexForLayer(layer, position, 0);
345: }
346:
347: private int insertIndexForLayer(final int layer,
348: final int position, final int startPosition) {
349: assert startPosition == 0
350: || getLayer(getComponent(startPosition - 1)) > layer : "startPosition in the middle of the current layer";
351: if (getComponentCount() == 0) {
352: return 0;
353: }
354: // the bottommost position of layer n
355: // is equivalent to topmost position of level n-1
356: int adjustedPosition = position;
357: int adjustedLayer = layer;
358: if (position == -1) {
359: adjustedPosition = 0;
360: adjustedLayer = layer - 1;
361: }
362: int result = startPosition;
363: // looking position depending on layer
364: for (; result < getComponentCount(); result++) {
365: if (getLayer(getComponent(result)) <= adjustedLayer) {
366: break;
367: }
368: }
369: // looking for position depending on index in layer
370: for (; result < getComponentCount() && adjustedPosition > 0; result++, adjustedPosition--) {
371: if (getLayer(getComponent(result)) != adjustedLayer) {
372: break;
373: }
374: }
375: return result;
376: }
377:
378: @Override
379: public void remove(final int index) {
380: Component comp = getComponent(index);
381: getComponentToLayer().remove(comp);
382: super .remove(index);
383: }
384:
385: @Override
386: public void removeAll() {
387: for (int i = getComponentCount() - 1; i >= 0; i--) {
388: remove(i);
389: }
390: }
391:
392: public int getComponentCountInLayer(final int layer) {
393: if (layer < lowestLayer() || layer > highestLayer()) {
394: return 0;
395: }
396: int start = insertIndexForLayer(layer, 0);
397: return insertIndexForLayer(layer, -1, start) - start;
398: }
399:
400: @Override
401: public boolean isOptimizedDrawingEnabled() {
402: return getComponentCount() <= 1;
403: }
404:
405: public int lowestLayer() {
406: if (getComponentCount() == 0) {
407: return 0;
408: }
409: return getLayer(getComponent(getComponentCount() - 1));
410: }
411:
412: public int highestLayer() {
413: if (getComponentCount() == 0) {
414: return 0;
415: }
416: return getLayer(getComponent(0));
417: }
418:
419: public static JLayeredPane getLayeredPaneAbove(final Component c) {
420: return (JLayeredPane) SwingUtilities.getAncestorOfClass(
421: JLayeredPane.class, c);
422: }
423:
424: public static void putLayer(final JComponent c, final int layer) {
425: Integer l = (Integer) c.getClientProperty(LAYER_PROPERTY);
426: if (l == null || l.intValue() != layer) {
427: // the layer is really changed
428: c.putClientProperty(LAYER_PROPERTY, new Integer(layer));
429: }
430: }
431:
432: public static int getLayer(final JComponent c) {
433: Integer layer = ((Integer) c.getClientProperty(LAYER_PROPERTY));
434: return layer == null ? 0 : layer.intValue();
435: }
436:
437: private void rememberLayerForComponent(final Component c,
438: final int layer) {
439: if (c instanceof JComponent) {
440: putLayer((JComponent) c, layer);
441: }
442: getComponentToLayer().put(c, getObjectForLayer(layer));
443: }
444: }
|