001 /* FlowLayout.java -- Grid-based layout engine 002 Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package java.awt; 040 041 import java.io.Serializable; 042 043 /** This class implements a flow-based layout. Components are laid 044 * out in order from left to right. When a component cannot be placed 045 * without horizontal clipping, a new row is started. This class 046 * supports horizontal and vertical gaps. These are used for spacing 047 * between components. 048 * 049 * @author Tom Tromey (tromey@redhat.com) 050 * @author Aaron M. Renn (arenn@urbanophile.com) 051 */ 052 public class FlowLayout implements LayoutManager, Serializable 053 { 054 /** Constant that specifies left alignment. */ 055 public static final int LEFT = 0; 056 /** Constant that specifies center alignment. */ 057 public static final int CENTER = 1; 058 /** Constant that specifies right alignment. */ 059 public static final int RIGHT = 2; 060 061 /** Constant that specifies alignment to leading edge of container's 062 * orientation. */ 063 public static final int LEADING = 3; 064 /** Constant that specifies alignment to trailing edge of container's 065 * orientation. */ 066 public static final int TRAILING = 4; 067 068 // Serialization constant 069 private static final long serialVersionUID = -7262534875583282631L; 070 071 /** 072 * Add a new component to the layout. This particular implementation 073 * does nothing. 074 * 075 * @param name the name 076 * @param comp the component 077 */ 078 public void addLayoutComponent (String name, Component comp) 079 { 080 // Nothing. 081 } 082 083 /** 084 * Returns the current justification value for this object. 085 * 086 * @return The current justification value for this object. 087 */ 088 public int getAlignment () 089 { 090 return align; 091 } 092 093 /** 094 * Returns the horizontal gap between components. 095 * 096 * @return The horizontal gap between components. 097 */ 098 public int getHgap () 099 { 100 return hgap; 101 } 102 103 /** 104 * Returns the vertical gap between lines of components. 105 * 106 * @return The vertical gap between lines of components. 107 */ 108 public int getVgap () 109 { 110 return vgap; 111 } 112 113 /** 114 * Initializes a new instance of <code>FlowLayout</code> with a center 115 * justification and a default horizontal and vertical gap of 5. 116 */ 117 public FlowLayout () 118 { 119 this (CENTER, 5, 5); 120 } 121 122 /** 123 * Initializes a new instance of <code>FlowLayout</code> with the specified 124 * justification and a default horizontal and vertical gap of 5. 125 * 126 * @param align The justification setting, which should be one of the 127 * contants in this class. 128 */ 129 public FlowLayout (int align) 130 { 131 this (align, 5, 5); 132 } 133 134 /** 135 * Initializes a new instance of <code>FlowLayout</code> with the specified 136 * justification and gap values 137 * @param align Alignment 138 * @param hgap The horizontal gap 139 * @param vgap The vertical gap 140 * @exception IllegalArgumentException If either gap is negative 141 */ 142 public FlowLayout (int align, int hgap, int vgap) 143 { 144 // Use methods to set fields so that we can have all the checking 145 // in one place. 146 setVgap (vgap); 147 setHgap (hgap); 148 setAlignment (align); 149 } 150 151 /** Lay out the container's components based on current settings. 152 * @param parent The parent container 153 */ 154 public void layoutContainer (Container parent) 155 { 156 synchronized (parent.getTreeLock ()) 157 { 158 int num = parent.getComponentCount (); 159 // This is more efficient than calling getComponents(). 160 Component[] comps = parent.component; 161 162 Dimension d = parent.getSize (); 163 Insets ins = parent.getInsets (); 164 165 ComponentOrientation orient = parent.getComponentOrientation (); 166 boolean left_to_right = orient.isLeftToRight (); 167 168 int y = ins.top + vgap; 169 int i = 0; 170 while (i < num) 171 { 172 // Find the components which go in the current row. 173 int new_w = ins.left + hgap + ins.right; 174 int new_h = 0; 175 int j; 176 boolean found_one = false; 177 for (j = i; j < num; ++j) 178 { 179 // Skip invisible items. 180 if (! comps[j].visible) 181 continue; 182 183 Dimension c = comps[j].getPreferredSize (); 184 185 int next_w = new_w + hgap + c.width; 186 if (next_w <= d.width || ! found_one) 187 { 188 new_w = next_w; 189 new_h = Math.max (new_h, c.height); 190 found_one = true; 191 } 192 else 193 { 194 // Must start a new row, and we already found an item 195 break; 196 } 197 } 198 199 // Set the location of each component for this row. 200 int x; 201 202 int myalign = align; 203 if (align == LEADING) 204 myalign = left_to_right ? LEFT : RIGHT; 205 else if (align == TRAILING) 206 myalign = left_to_right ? RIGHT : LEFT; 207 208 if (myalign == RIGHT) 209 x = ins.left + (d.width - new_w) + hgap; 210 else if (myalign == CENTER) 211 x = ins.left + (d.width - new_w) / 2 + hgap; 212 else // LEFT and all other values of align. 213 x = ins.left + hgap; 214 215 for (int k = i; k < j; ++k) 216 { 217 if (comps[k].visible) 218 { 219 Dimension c = comps[k].getPreferredSize (); 220 comps[k].setBounds (x, y + (new_h - c.height) / 2, 221 c.width, c.height); 222 x += c.width + hgap; 223 } 224 } 225 226 // Advance to next row. 227 i = j; 228 y += new_h + vgap; 229 } 230 } 231 } 232 233 /** 234 * Returns the minimum layout size for the specified container using 235 * this layout. 236 * @param cont The parent container 237 * @return The minimum layout size. 238 */ 239 public Dimension minimumLayoutSize (Container cont) 240 { 241 return getSize (cont, true); 242 } 243 244 /** 245 * Returns the preferred layout size for the specified container using 246 * this layout. 247 * @param cont The parent container 248 * @return The preferred layout size. 249 */ 250 public Dimension preferredLayoutSize (Container cont) 251 { 252 return getSize (cont, false); 253 } 254 255 /** Remove the indicated component from this layout manager. 256 * This particular implementation does nothing. 257 * @param comp The component to remove 258 */ 259 public void removeLayoutComponent (Component comp) 260 { 261 // Nothing. 262 } 263 264 /** 265 * Sets the justification value for this object to the specified value. 266 * 267 * @param align The new justification value for this object, which must 268 * be one of the constants in this class. 269 */ 270 public void setAlignment (int align) 271 { 272 // The JDK accepts invalid values and treats them as 273 // LEFT during layout, so do we. The invalid value is even stored, 274 // getAlignment() returns the same invalid value. 275 this.align = align; 276 } 277 278 /** 279 * Sets the horizontal gap between lines of components to the specified value. 280 * No Exception is thrown if hgap < 0. 281 * 282 * @param hgap The new horizontal gap between components. 283 */ 284 public void setHgap (int hgap) 285 { 286 this.hgap = hgap; 287 } 288 289 /** 290 * Sets the vertical gap between lines of components to the specified value. 291 * No Exception is thrown if vgap < 0. 292 * 293 * @param vgap The new vertical gap. 294 */ 295 public void setVgap (int vgap) 296 { 297 this.vgap = vgap; 298 } 299 300 /** Return String description of this object. 301 * @return A string representation of this object. 302 */ 303 public String toString () 304 { 305 return ("[" + getClass ().getName () + ",hgap=" + hgap + ",vgap=" + vgap 306 + ",align=" + align + "]"); 307 } 308 309 // This method is used to compute the various sizes. 310 private Dimension getSize (Container parent, boolean is_min) 311 { 312 synchronized (parent.getTreeLock ()) 313 { 314 int w, h, num = parent.getComponentCount (); 315 // This is more efficient than calling getComponents(). 316 Component[] comps = parent.component; 317 318 w = 0; 319 h = 0; 320 for (int i = 0; i < num; ++i) 321 { 322 if (! comps[i].visible) 323 continue; 324 325 // FIXME: can we just directly read the fields in Component? 326 // Or will that not work with subclassing? 327 Dimension d; 328 329 if (is_min) 330 d = comps[i].getMinimumSize (); 331 else 332 d = comps[i].getPreferredSize (); 333 334 w += d.width; 335 h = Math.max (d.height, h); 336 } 337 338 Insets ins = parent.getInsets (); 339 340 if (num == 0) 341 w += 2 * hgap + ins.left + ins.right; 342 else 343 w += (num + 1) * hgap + ins.left + ins.right; 344 h += 2 * vgap + ins.top + ins.bottom; 345 346 return new Dimension (w, h); 347 } 348 } 349 350 /** 351 * @serial The justification alignment of the lines of components, which 352 * will be one of the constants defined in this class. 353 */ 354 private int align; 355 356 /** 357 * @serial The horizontal gap between components. 358 */ 359 private int hgap; 360 361 /** 362 * @serial The vertical gap between lines of components. 363 */ 364 private int vgap; 365 }