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