001 /*
002 * $Id: StackLayout.java,v 1.2 2006/04/19 23:42:08 gfx Exp $
003 *
004 * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle,
005 * Santa Clara, California 95054, U.S.A. All rights reserved.
006 */
007
008 package org.jdesktop.swingx;
009
010 import java.awt.Component;
011 import java.awt.Container;
012 import java.awt.Dimension;
013 import java.awt.Insets;
014 import java.awt.LayoutManager2;
015 import java.awt.Rectangle;
016 import java.util.LinkedList;
017 import java.util.List;
018
019 /**
020 * <p><code>StackLayout</code> is a Swing layout aimed to act as the layers
021 * stack of most popuplar graphics editing tools like <i>The GIMP</i> or
022 * <i>Photoshop</i>. While similar to <code>CardLayout</code>, this layout
023 * displays all the components of the container. If you are using non-rectangular
024 * components (i.e. transparent) you will see them from top to bottom of the
025 * stack.</p>
026 * <p>When using this layout, each component can be added in the container
027 * either on top of the stack or at the bootom:</p>
028 * <pre>
029 * JPanel panel = new JPanel(new StackLayout());
030 * panel.add(new JLabel("On top"), StackLayout.TOP);
031 * panel.add(new JLabel("At bottom"), StackLayout.BOTTOM);
032 * </pre>
033 * If you don't specify the constraint, the component will be added at the top
034 * of the components stack.</p>
035 * <p>All the components managed by this layout will be given the same size as
036 * the container itself. The minimum, maximum and preferred size of the
037 * container are based upon the largest minimum, maximum and preferred size of
038 * the children components.</p>
039 * <p><code>StackLayout</code> works only with JSE 1.5 and Java SE 6 and
040 * greater.</p>
041 *
042 * @author Romain Guy <romain.guy@mac.com>
043 */
044
045 public class StackLayout implements LayoutManager2 {
046 /** Use this constraint to add a component at the bottom of the stack. */
047 public static final String BOTTOM = "bottom";
048 /** Use this contrainst to add a component at the top of the stack. */
049 public static final String TOP = "top";
050
051 // removing components does not happen often compared to adding components
052 // hence we choose a linked list to make insertion at the bottom faster
053 private List<Component> components = new LinkedList<Component>();
054
055 /**
056 * {@inheritDoc}
057 */
058 public void addLayoutComponent(final Component comp,
059 final Object constraints) {
060 synchronized (comp.getTreeLock()) {
061 if (BOTTOM.equals(constraints)) {
062 components.add(0, comp);
063 } else if (TOP.equals(constraints)) {
064 components.add(comp);
065 } else {
066 components.add(comp);
067 }
068 }
069 }
070
071 /**
072 * {@inheritDoc}
073 */
074 public void addLayoutComponent(final String name, final Component comp) {
075 addLayoutComponent(comp, TOP);
076 }
077
078 /**
079 * {@inheritDoc}
080 */
081 public void removeLayoutComponent(final Component comp) {
082 synchronized (comp.getTreeLock()) {
083 components.remove(comp);
084 }
085 }
086
087 /**
088 * {@inheritDoc}
089 */
090 public float getLayoutAlignmentX(final Container target) {
091 return 0.5f;
092 }
093
094 /**
095 * {@inheritDoc}
096 */
097 public float getLayoutAlignmentY(final Container target) {
098 return 0.5f;
099 }
100
101 /**
102 * {@inheritDoc}
103 */
104 public void invalidateLayout(final Container target) {
105 }
106
107 /**
108 * {@inheritDoc}
109 */
110 public Dimension preferredLayoutSize(final Container parent) {
111 synchronized (parent.getTreeLock()) {
112 int width = 0;
113 int height = 0;
114
115 for (Component comp: components) {
116 Dimension size = comp.getPreferredSize();
117 width = Math.max(size.width, width);
118 height = Math.max(size.height, height);
119 }
120
121 Insets insets = parent.getInsets();
122 width += insets.left + insets.right;
123 height += insets.top + insets.bottom;
124
125 return new Dimension(width, height);
126 }
127 }
128
129 /**
130 * {@inheritDoc}
131 */
132 public Dimension minimumLayoutSize(final Container parent) {
133 synchronized (parent.getTreeLock()) {
134 int width = 0;
135 int height = 0;
136
137 for (Component comp: components) {
138 Dimension size = comp.getMinimumSize();
139 width = Math.max(size.width, width);
140 height = Math.max(size.height, height);
141 }
142
143 Insets insets = parent.getInsets();
144 width += insets.left + insets.right;
145 height += insets.top + insets.bottom;
146
147 return new Dimension(width, height);
148 }
149 }
150
151 /**
152 * {@inheritDoc}
153 */
154 public Dimension maximumLayoutSize(final Container target) {
155 return new Dimension(Integer.MAX_VALUE,
156 Integer.MAX_VALUE);
157 }
158
159 /**
160 * {@inheritDoc}
161 */
162 public void layoutContainer(final Container parent) {
163 synchronized (parent.getTreeLock()) {
164 int width = parent.getWidth();
165 int height = parent.getHeight();
166
167 Rectangle bounds = new Rectangle(0, 0, width, height);
168
169 int componentsCount = components.size();
170
171 for (int i = 0; i < componentsCount; i++) {
172 Component comp = components.get(i);
173 comp.setBounds(bounds);
174 parent.setComponentZOrder(comp, componentsCount - i - 1);
175 }
176 }
177 }
178 }