Frames | No Frames |
1: /* FlowLayout.java -- Grid-based layout engine 2: Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation 3: 4: This file is part of GNU Classpath. 5: 6: GNU Classpath is free software; you can redistribute it and/or modify 7: it under the terms of the GNU General Public License as published by 8: the Free Software Foundation; either version 2, or (at your option) 9: any later version. 10: 11: GNU Classpath is distributed in the hope that it will be useful, but 12: WITHOUT ANY WARRANTY; without even the implied warranty of 13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14: General Public License for more details. 15: 16: You should have received a copy of the GNU General Public License 17: along with GNU Classpath; see the file COPYING. If not, write to the 18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19: 02110-1301 USA. 20: 21: Linking this library statically or dynamically with other modules is 22: making a combined work based on this library. Thus, the terms and 23: conditions of the GNU General Public License cover the whole 24: combination. 25: 26: As a special exception, the copyright holders of this library give you 27: permission to link this library with independent modules to produce an 28: executable, regardless of the license terms of these independent 29: modules, and to copy and distribute the resulting executable under 30: terms of your choice, provided that you also meet, for each linked 31: independent module, the terms and conditions of the license of that 32: module. An independent module is a module which is not derived from 33: or based on this library. If you modify this library, you may extend 34: this exception to your version of the library, but you are not 35: obligated to do so. If you do not wish to do so, delete this 36: exception statement from your version. */ 37: 38: 39: package java.awt; 40: 41: import java.io.Serializable; 42: 43: /** This class implements a flow-based layout. Components are laid 44: * out in order from left to right. When a component cannot be placed 45: * without horizontal clipping, a new row is started. This class 46: * supports horizontal and vertical gaps. These are used for spacing 47: * between components. 48: * 49: * @author Tom Tromey (tromey@redhat.com) 50: * @author Aaron M. Renn (arenn@urbanophile.com) 51: */ 52: public class FlowLayout implements LayoutManager, Serializable 53: { 54: /** Constant that specifies left alignment. */ 55: public static final int LEFT = 0; 56: /** Constant that specifies center alignment. */ 57: public static final int CENTER = 1; 58: /** Constant that specifies right alignment. */ 59: public static final int RIGHT = 2; 60: 61: /** Constant that specifies alignment to leading edge of container's 62: * orientation. */ 63: public static final int LEADING = 3; 64: /** Constant that specifies alignment to trailing edge of container's 65: * orientation. */ 66: public static final int TRAILING = 4; 67: 68: // Serialization constant 69: private static final long serialVersionUID = -7262534875583282631L; 70: 71: /** 72: * Add a new component to the layout. This particular implementation 73: * does nothing. 74: * 75: * @param name the name 76: * @param comp the component 77: */ 78: public void addLayoutComponent (String name, Component comp) 79: { 80: // Nothing. 81: } 82: 83: /** 84: * Returns the current justification value for this object. 85: * 86: * @return The current justification value for this object. 87: */ 88: public int getAlignment () 89: { 90: return align; 91: } 92: 93: /** 94: * Returns the horizontal gap between components. 95: * 96: * @return The horizontal gap between components. 97: */ 98: public int getHgap () 99: { 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: }