001/* 002 * $Id: StackLayout.java 3793 2010-09-28 05:15:02Z kschaefe $ 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 */ 021package org.jdesktop.swingx; 022 023import java.awt.Component; 024import java.awt.Container; 025import java.awt.Dimension; 026import java.awt.Insets; 027import java.awt.LayoutManager2; 028import java.awt.Rectangle; 029import java.util.LinkedList; 030import 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 bottom:</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 058public 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 @Override 072 public void addLayoutComponent(final Component comp, 073 final Object constraints) { 074 synchronized (comp.getTreeLock()) { 075 if (BOTTOM.equals(constraints)) { 076 components.add(0, comp); 077 } else if (TOP.equals(constraints)) { 078 components.add(comp); 079 } else { 080 components.add(comp); 081 } 082 } 083 } 084 085 /** 086 * {@inheritDoc} 087 */ 088 @Override 089 public void addLayoutComponent(final String name, final Component comp) { 090 addLayoutComponent(comp, TOP); 091 } 092 093 /** 094 * {@inheritDoc} 095 */ 096 @Override 097 public void removeLayoutComponent(final Component comp) { 098 synchronized (comp.getTreeLock()) { 099 components.remove(comp); 100 } 101 } 102 103 /** 104 * {@inheritDoc} 105 */ 106 @Override 107 public float getLayoutAlignmentX(final Container target) { 108 return 0.5f; 109 } 110 111 /** 112 * {@inheritDoc} 113 */ 114 @Override 115 public float getLayoutAlignmentY(final Container target) { 116 return 0.5f; 117 } 118 119 /** 120 * {@inheritDoc} 121 */ 122 @Override 123 public void invalidateLayout(final Container target) { 124 } 125 126 /** 127 * {@inheritDoc} 128 */ 129 @Override 130 public Dimension preferredLayoutSize(final Container parent) { 131 synchronized (parent.getTreeLock()) { 132 int width = 0; 133 int height = 0; 134 135 for (Component comp: components) { 136 Dimension size = comp.getPreferredSize(); 137 width = Math.max(size.width, width); 138 height = Math.max(size.height, height); 139 } 140 141 Insets insets = parent.getInsets(); 142 width += insets.left + insets.right; 143 height += insets.top + insets.bottom; 144 145 return new Dimension(width, height); 146 } 147 } 148 149 /** 150 * {@inheritDoc} 151 */ 152 @Override 153 public Dimension minimumLayoutSize(final Container parent) { 154 synchronized (parent.getTreeLock()) { 155 int width = 0; 156 int height = 0; 157 158 for (Component comp: components) { 159 Dimension size = comp.getMinimumSize(); 160 width = Math.max(size.width, width); 161 height = Math.max(size.height, height); 162 } 163 164 Insets insets = parent.getInsets(); 165 width += insets.left + insets.right; 166 height += insets.top + insets.bottom; 167 168 return new Dimension(width, height); 169 } 170 } 171 172 /** 173 * {@inheritDoc} 174 */ 175 @Override 176 public Dimension maximumLayoutSize(final Container target) { 177 return new Dimension(Integer.MAX_VALUE, 178 Integer.MAX_VALUE); 179 } 180 181 /** 182 * {@inheritDoc} 183 */ 184 @Override 185 public void layoutContainer(final Container parent) { 186 synchronized (parent.getTreeLock()) { 187 int width = parent.getWidth(); 188 int height = parent.getHeight(); 189 190 Rectangle bounds = new Rectangle(0, 0, width, height); 191 192 int componentsCount = components.size(); 193 194 for (int i = 0; i < componentsCount; i++) { 195 Component comp = components.get(i); 196 comp.setBounds(bounds); 197 parent.setComponentZOrder(comp, componentsCount - i - 1); 198 } 199 } 200 } 201}