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 }