GNU Classpath (0.20) | |
Frames | No Frames |
1: /* CardLayout.java -- Card-based layout engine 2: Copyright (C) 1999, 2000, 2002, 2003, 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: import java.util.Enumeration; 43: import java.util.Hashtable; 44: 45: /** 46: * This class implements a card-based layout scheme. Each included 47: * component is treated as a card. Only one card can be shown at a 48: * time. This class includes methods for changing which card is 49: * shown. 50: * 51: * @author Tom Tromey (tromey@redhat.com) 52: * @author Aaron M. Renn (arenn@urbanophile.com) 53: */ 54: public class CardLayout implements LayoutManager2, Serializable 55: { 56: private static final long serialVersionUID = -4328196481005934313L; 57: 58: /** 59: * Initializes a new instance of <code>CardLayout</code> with horizontal 60: * and vertical gaps of 0. 61: */ 62: public CardLayout () 63: { 64: this (0, 0); 65: } 66: 67: /** 68: * Create a new <code>CardLayout</code> object with the specified 69: * horizontal and vertical gaps. 70: * 71: * @param hgap The horizontal gap 72: * @param vgap The vertical gap 73: */ 74: public CardLayout (int hgap, int vgap) 75: { 76: this.hgap = hgap; 77: this.vgap = vgap; 78: this.tab = new Hashtable (); 79: } 80: 81: /** 82: * Add a new component to the layout. The constraint must be a 83: * string which is used to name the component. This string can 84: * later be used to refer to the particular component. 85: * 86: * @param comp The component to add 87: * @param constraints The name by which the component can later be called 88: * 89: * @exception IllegalArgumentException If `constraints' is not a 90: * <code>String</code> 91: */ 92: public void addLayoutComponent (Component comp, Object constraints) 93: { 94: if (! (constraints instanceof String)) 95: throw new IllegalArgumentException ("Object " + constraints 96: + " is not a string"); 97: addLayoutComponent ((String) constraints, comp); 98: } 99: 100: /** 101: * Add a new component to the layout. The name can be used later 102: * to refer to the component. 103: * 104: * @param name The name by which the component can later be called 105: * @param comp The component to add 106: * 107: * @deprecated This method is deprecated in favor of 108: * <code>addLayoutComponent(Component, Object)</code>. 109: */ 110: public void addLayoutComponent (String name, Component comp) 111: { 112: tab.put (name, comp); 113: // First component added is the default component. 114: comp.setVisible(tab.size() == 1); 115: } 116: 117: /** 118: * Cause the first component in the container to be displayed. 119: * 120: * @param parent The parent container 121: */ 122: public void first (Container parent) 123: { 124: gotoComponent (parent, FIRST); 125: } 126: 127: /** 128: * Return this layout manager's horizontal gap. 129: * 130: * @return the horizontal gap 131: */ 132: public int getHgap () 133: { 134: return hgap; 135: } 136: 137: /** 138: * Return this layout manager's x alignment. This method always 139: * returns Component.CENTER_ALIGNMENT. 140: * 141: * @param parent Container using this layout manager instance 142: * 143: * @return the x-axis alignment 144: */ 145: public float getLayoutAlignmentX (Container parent) 146: { 147: return Component.CENTER_ALIGNMENT; 148: } 149: 150: /** 151: * Returns this layout manager's y alignment. This method always 152: * returns Component.CENTER_ALIGNMENT. 153: * 154: * @param parent Container using this layout manager instance 155: * 156: * @return the y-axis alignment 157: */ 158: public float getLayoutAlignmentY (Container parent) 159: { 160: return Component.CENTER_ALIGNMENT; 161: } 162: 163: /** 164: * Return this layout manager's vertical gap. 165: * 166: * @return the vertical gap 167: */ 168: public int getVgap () 169: { 170: return vgap; 171: } 172: 173: /** 174: * Invalidate this layout manager's state. 175: */ 176: public void invalidateLayout (Container target) 177: { 178: // Do nothing. 179: } 180: 181: /** 182: * Cause the last component in the container to be displayed. 183: * 184: * @param parent The parent container 185: */ 186: public void last (Container parent) 187: { 188: gotoComponent (parent, LAST); 189: } 190: 191: /** 192: * Lays out the container. This is done by resizing the child components 193: * to be the same size as the parent, less insets and gaps. 194: * 195: * @param parent The parent container. 196: */ 197: public void layoutContainer (Container parent) 198: { 199: synchronized (parent.getTreeLock ()) 200: { 201: int width = parent.width; 202: int height = parent.height; 203: 204: Insets ins = parent.getInsets (); 205: 206: int num = parent.ncomponents; 207: Component[] comps = parent.component; 208: 209: int x = ins.left + hgap; 210: int y = ins.top + vgap; 211: width = width - 2 * hgap - ins.left - ins.right; 212: height = height - 2 * vgap - ins.top - ins.bottom; 213: 214: for (int i = 0; i < num; ++i) 215: comps[i].setBounds (x, y, width, height); 216: } 217: } 218: 219: /** 220: * Get the maximum layout size of the container. 221: * 222: * @param target The parent container 223: * 224: * @return the maximum layout size 225: */ 226: public Dimension maximumLayoutSize (Container target) 227: { 228: // The JCL says that this returns Integer.MAX_VALUE for both 229: // dimensions. But that just seems wrong to me. 230: return getSize (target, MAX); 231: } 232: 233: /** 234: * Get the minimum layout size of the container. 235: * 236: * @param target The parent container 237: * 238: * @return the minimum layout size 239: */ 240: public Dimension minimumLayoutSize (Container target) 241: { 242: return getSize (target, MIN); 243: } 244: 245: /** 246: * Cause the next component in the container to be displayed. If 247: * this current card is the last one in the deck, the first 248: * component is displayed. 249: * 250: * @param parent The parent container 251: */ 252: public void next (Container parent) 253: { 254: gotoComponent (parent, NEXT); 255: } 256: 257: /** 258: * Get the preferred layout size of the container. 259: * 260: * @param parent The parent container 261: * 262: * @return the preferred layout size 263: */ 264: public Dimension preferredLayoutSize (Container parent) 265: { 266: return getSize (parent, PREF); 267: } 268: 269: /** 270: * Cause the previous component in the container to be displayed. 271: * If this current card is the first one in the deck, the last 272: * component is displayed. 273: * 274: * @param parent The parent container 275: */ 276: public void previous (Container parent) 277: { 278: gotoComponent (parent, PREV); 279: } 280: 281: /** 282: * Remove the indicated component from this layout manager. 283: * 284: * @param comp The component to remove 285: */ 286: public void removeLayoutComponent (Component comp) 287: { 288: Enumeration e = tab.keys (); 289: while (e.hasMoreElements ()) 290: { 291: Object key = e.nextElement (); 292: if (tab.get (key) == comp) 293: { 294: tab.remove (key); 295: Container parent = comp.getParent(); 296: next(parent); 297: break; 298: } 299: } 300: } 301: 302: /** 303: * Set this layout manager's horizontal gap. 304: * 305: * @param hgap The new gap 306: */ 307: public void setHgap (int hgap) 308: { 309: this.hgap = hgap; 310: } 311: 312: /** 313: * Set this layout manager's vertical gap. 314: * 315: * @param vgap The new gap 316: */ 317: public void setVgap (int vgap) 318: { 319: this.vgap = vgap; 320: } 321: 322: /** 323: * Cause the named component to be shown. If the component name is 324: * unknown, this method does nothing. 325: * 326: * @param parent The parent container 327: * @param name The name of the component to show 328: */ 329: public void show (Container parent, String name) 330: { 331: Object target = tab.get (name); 332: if (target != null) 333: { 334: int num = parent.ncomponents; 335: // This is more efficient than calling getComponents(). 336: Component[] comps = parent.component; 337: for (int i = 0; i < num; ++i) 338: { 339: if (comps[i].isVisible()) 340: { 341: if (target == comps[i]) 342: return; 343: comps[i].setVisible (false); 344: } 345: } 346: ((Component) target).setVisible (true); 347: } 348: } 349: 350: /** 351: * Returns a string representation of this layout manager. 352: * 353: * @return A string representation of this object. 354: */ 355: public String toString () 356: { 357: return getClass ().getName () + "[" + hgap + "," + vgap + "]"; 358: } 359: 360: /** 361: * This implements first(), last(), next(), and previous(). 362: * 363: * @param parent The parent container 364: * @param what The type of goto: FIRST, LAST, NEXT or PREV 365: */ 366: private void gotoComponent (Container parent, int what) 367: { 368: synchronized (parent.getTreeLock ()) 369: { 370: int num = parent.ncomponents; 371: // This is more efficient than calling getComponents(). 372: Component[] comps = parent.component; 373: 374: if (num == 1) 375: { 376: comps[0].setVisible(true); 377: return; 378: } 379: 380: int choice = -1; 381: 382: if (what == FIRST) 383: choice = 0; 384: else if (what == LAST) 385: choice = num - 1; 386: 387: for (int i = 0; i < num; ++i) 388: { 389: if (comps[i].isVisible ()) 390: { 391: if (what == NEXT) 392: { 393: choice = i + 1; 394: if (choice == num) 395: choice = 0; 396: } 397: else if (what == PREV) 398: { 399: choice = i - 1; 400: if (choice < 0) 401: choice = num - 1; 402: } 403: else if (choice == i) 404: { 405: // Do nothing if we're already looking at the right 406: // component. 407: return; 408: } 409: comps[i].setVisible (false); 410: 411: if (choice >= 0) 412: break; 413: } 414: } 415: 416: if (choice >= 0 && choice < num) 417: comps[choice].setVisible (true); 418: } 419: } 420: 421: // Compute the size according to WHAT. 422: private Dimension getSize (Container parent, int what) 423: { 424: synchronized (parent.getTreeLock ()) 425: { 426: int w = 0, h = 0, num = parent.ncomponents; 427: Component[] comps = parent.component; 428: 429: for (int i = 0; i < num; ++i) 430: { 431: Dimension d; 432: 433: if (what == MIN) 434: d = comps[i].getMinimumSize (); 435: else if (what == MAX) 436: d = comps[i].getMaximumSize (); 437: else 438: d = comps[i].getPreferredSize (); 439: 440: w = Math.max (d.width, w); 441: h = Math.max (d.height, h); 442: } 443: 444: Insets i = parent.getInsets (); 445: w += 2 * hgap + i.right + i.left; 446: h += 2 * vgap + i.bottom + i.top; 447: 448: // Handle overflow. 449: if (w < 0) 450: w = Integer.MAX_VALUE; 451: if (h < 0) 452: h = Integer.MAX_VALUE; 453: 454: return new Dimension (w, h); 455: } 456: } 457: 458: /** 459: * @serial Horizontal gap value. 460: */ 461: private int hgap; 462: 463: /** 464: * @serial Vertical gap value. 465: */ 466: private int vgap; 467: 468: /** 469: * @serial Table of named components. 470: */ 471: private Hashtable tab; 472: 473: // These constants are used by the private gotoComponent method. 474: private static final int FIRST = 0; 475: private static final int LAST = 1; 476: private static final int NEXT = 2; 477: private static final int PREV = 3; 478: 479: // These constants are used by the private getSize method. 480: private static final int MIN = 0; 481: private static final int MAX = 1; 482: private static final int PREF = 2; 483: }
GNU Classpath (0.20) |