001/* 002 * IzPack - Copyright 2001-2005 Julien Ponge, All Rights Reserved. 003 * 004 * http://www.izforge.com/izpack/ 005 * http://developer.berlios.de/projects/izpack/ 006 * 007 * Copyright 2002 Elmar Grom 008 * 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 */ 021 022package com.izforge.izpack.gui; 023 024import java.awt.Component; 025import java.awt.Container; 026import java.awt.Dimension; 027import java.awt.Insets; 028import java.awt.LayoutManager; 029 030/*---------------------------------------------------------------------------*/ 031/** 032 * A flow layout arranges components in a left-to-right flow, much like lines of text in a 033 * paragraph. Flow layouts are typically used to arrange buttons in a panel. It will arrange buttons 034 * left to right until no more buttons fit on the same line. Each line is centered. 035 * <p> 036 * For example, the following picture shows an applet using the flow layout manager (its default 037 * layout manager) to position three buttons: 038 * <p> 039 * <img src="doc-files/FlowLayout-1.gif" ALT="Graphic of Layout for Three Buttons" ALIGN=center 040 * HSPACE=10 VSPACE=7> 041 * <p> 042 * Here is the code for this applet: 043 * <p> 044 * <hr> 045 * <blockquote> 046 * 047 * <pre> 048 * import java.awt.*; 049 * import java.applet.Applet; 050 * 051 * public class myButtons extends Applet 052 * { 053 * 054 * Button button1, button2, button3; 055 * 056 * public void init() 057 * { 058 * button1 = new Button("Ok"); 059 * button2 = new Button("Open"); 060 * button3 = new Button("Close"); 061 * add(button1); 062 * add(button2); 063 * add(button3); 064 * } 065 * } 066 * 067 * </pre> 068 * 069 * </blockquote> 070 * <hr> 071 * <p> 072 * A flow layout lets each component assume its natural (preferred) size. 073 * 074 * This class is a bit different from java.awt.FlowLayout. <blockquote> java.awt.FlowLayout has a 075 * minor problem that was bugging me when I wrote the UserInputPanel. FlowLayout puts some amount of 076 * space in between each component that it lays out. In addition it adds that same amount of space 077 * to the left and to the right of the entire group. Therefore items such as the RuleInputfield that 078 * are laid out with a FlowLayout would never line up properly with the other components (it would 079 * appear to be slightly indented). Because there is no way to circumvent this behavior in 080 * FlowLayout (it's hard coded) I copied the source and modified it so that it does not add the 081 * space to the left and to the right. Now my stuff lines up properly. (Elmar Grom)</blockquote> 082 * 083 * @version 1.39, 11/29/02 084 * @author Arthur van Hoff 085 * @author Sami Shaio 086 * @author Elmar Grom 087 */ 088/*---------------------------------------------------------------------------*/ 089public class FlowLayout implements LayoutManager 090{ 091 092 /** 093 * This value indicates that each row of components should be left-justified. 094 */ 095 public static final int LEFT = 0; 096 097 /** 098 * This value indicates that each row of components should be centered. 099 */ 100 public static final int CENTER = 1; 101 102 /** 103 * This value indicates that each row of components should be right-justified. 104 */ 105 public static final int RIGHT = 2; 106 107 /** 108 * This value indicates that each row of components should be justified to the leading edge of 109 * the container's orientation, for example, to the left in left-to-right orientations. 110 * 111 * @see java.awt.Component#getComponentOrientation 112 * @see java.awt.ComponentOrientation 113 * @since 1.2 Package-private pending API change approval 114 */ 115 public static final int LEADING = 3; 116 117 /** 118 * This value indicates that each row of components should be justified to the leading edge of 119 * the container's orientation, for example, to the right in left-to-right orientations. 120 * 121 * @see java.awt.Component#getComponentOrientation 122 * @see java.awt.ComponentOrientation 123 * @since 1.2 Package-private pending API change approval 124 */ 125 public static final int TRAILING = 4; 126 127 /** 128 * <code>align</code> is the proprty that determines how each row distributes empty space. It 129 * can be one of the following three values : <code>LEFT</code> 130 * <code>RIGHT</code> 131 * <code>CENTER</code> 132 * 133 * @serial 134 * @see #getAlignment 135 * @see #setAlignment 136 */ 137 int align; // This is for 1.1 serialization compatibilitys 138 139 /** 140 * <code>newAlign</code> is the property that determines how each row distributes empty space 141 * for the Java 2 platform, v1.2 and greater. It can be one of the following three values : 142 * <code>LEFT</code> 143 * <code>RIGHT</code> 144 * <code>CENTER</code> 145 * 146 * @serial 147 * @since 1.2 148 * @see #getAlignment 149 * @see #setAlignment 150 */ 151 int newAlign; // This is the one we actually use 152 153 /** 154 * The flow layout manager allows a seperation of components with gaps. The horizontal gap will 155 * specify the space between components. 156 * 157 * @serial 158 * @see #getHgap 159 * @see #setHgap 160 */ 161 int hgap; 162 163 /** 164 * The flow layout manager allows a seperation of components with gaps. The vertical gap will 165 * specify the space between rows. 166 * 167 * @serial 168 * @see #getVgap 169 * @see #setVgap 170 */ 171 int vgap; 172 173 /*--------------------------------------------------------------------------*/ 174 /** 175 * Constructs a new Flow Layout with a centered alignment and a default 5-unit horizontal and 176 * vertical gap. 177 */ 178 /*--------------------------------------------------------------------------*/ 179 public FlowLayout() 180 { 181 this(CENTER, 5, 5); 182 } 183 184 /*--------------------------------------------------------------------------*/ 185 /** 186 * Constructs a new Flow Layout with the specified alignment and a default 5-unit horizontal and 187 * vertical gap. The value of the alignment argument must be one of <code>FlowLayout.LEFT</code>, 188 * <code>FlowLayout.RIGHT</code>, or <code>FlowLayout.CENTER</code>. 189 * 190 * @param align the alignment value 191 */ 192 /*--------------------------------------------------------------------------*/ 193 public FlowLayout(int align) 194 { 195 this(align, 5, 5); 196 } 197 198 /*--------------------------------------------------------------------------*/ 199 /** 200 * Creates a new flow layout manager with the indicated alignment and the indicated horizontal 201 * and vertical gaps. 202 * <p> 203 * The value of the alignment argument must be one of <code>FlowLayout.LEFT</code>, 204 * <code>FlowLayout.RIGHT</code>, or <code>FlowLayout.CENTER</code>. 205 * 206 * @param align the alignment value. 207 * @param hgap the horizontal gap between components. 208 * @param vgap the vertical gap between components. 209 */ 210 /*--------------------------------------------------------------------------*/ 211 public FlowLayout(int align, int hgap, int vgap) 212 { 213 this.hgap = hgap; 214 this.vgap = vgap; 215 setAlignment(align); 216 } 217 218 /*--------------------------------------------------------------------------*/ 219 /** 220 * Gets the alignment for this layout. Possible values are <code>FlowLayout.LEFT</code>, 221 * <code>FlowLayout.RIGHT</code>, or <code>FlowLayout.CENTER</code>. 222 * 223 * @return the alignment value for this layout. 224 * 225 * @see java.awt.FlowLayout#setAlignment 226 */ 227 /*--------------------------------------------------------------------------*/ 228 public int getAlignment() 229 { 230 return (newAlign); 231 } 232 233 /*--------------------------------------------------------------------------*/ 234 /** 235 * Sets the alignment for this layout. Possible values are <code>FlowLayout.LEFT</code>, 236 * <code>FlowLayout.RIGHT</code>, and <code>FlowLayout.CENTER</code>. 237 * 238 * @param align the alignment value. 239 * 240 * @see #getAlignment() 241 */ 242 /*--------------------------------------------------------------------------*/ 243 public void setAlignment(int align) 244 { 245 this.newAlign = align; 246 247 // this.align is used only for serialization compatibility, 248 // so set it to a value compatible with the 1.1 version 249 // of the class 250 251 switch (align) 252 { 253 case LEADING: 254 this.align = LEFT; 255 break; 256 case TRAILING: 257 this.align = RIGHT; 258 break; 259 default: 260 this.align = align; 261 break; 262 } 263 } 264 265 /*--------------------------------------------------------------------------*/ 266 /** 267 * Gets the horizontal gap between components. 268 * 269 * @return the horizontal gap between components. 270 * 271 * @see #setHgap(int) 272 */ 273 /*--------------------------------------------------------------------------*/ 274 public int getHgap() 275 { 276 return (hgap); 277 } 278 279 /*--------------------------------------------------------------------------*/ 280 /** 281 * Sets the horizontal gap between components. 282 * 283 * @param hgap the horizontal gap between components 284 * 285 * @see #getHgap() 286 */ 287 /*--------------------------------------------------------------------------*/ 288 public void setHgap(int hgap) 289 { 290 this.hgap = hgap; 291 } 292 293 /*--------------------------------------------------------------------------*/ 294 /** 295 * Gets the vertical gap between components. 296 * 297 * @return the vertical gap between components.\ 298 * 299 * @see #setVgap(int) 300 */ 301 /*--------------------------------------------------------------------------*/ 302 public int getVgap() 303 { 304 return (vgap); 305 } 306 307 /*--------------------------------------------------------------------------*/ 308 /** 309 * Sets the vertical gap between components. 310 * 311 * @param vgap the vertical gap between components 312 * 313 * @see #getVgap() 314 */ 315 /*--------------------------------------------------------------------------*/ 316 public void setVgap(int vgap) 317 { 318 this.vgap = vgap; 319 } 320 321 /*--------------------------------------------------------------------------*/ 322 /** 323 * Adds the specified component to the layout. Not used by this class. 324 * 325 * @param name the name of the component 326 * @param comp the component to be added 327 */ 328 /*--------------------------------------------------------------------------*/ 329 public void addLayoutComponent(String name, Component comp) 330 { 331 } 332 333 /*--------------------------------------------------------------------------*/ 334 /** 335 * Removes the specified component from the layout. Not used by this class. 336 * 337 * @param comp the component to remove 338 * 339 */ 340 /*--------------------------------------------------------------------------*/ 341 public void removeLayoutComponent(Component comp) 342 { 343 } 344 345 /*--------------------------------------------------------------------------*/ 346 /** 347 * Returns the preferred dimensions for this layout given the components in the specified target 348 * container. 349 * 350 * @param target the component which needs to be laid out 351 * 352 * @return the preferred dimensions to lay out the subcomponents of the specified container. 353 * @see #minimumLayoutSize(Container) 354 */ 355 /*--------------------------------------------------------------------------*/ 356 public Dimension preferredLayoutSize(Container target) 357 { 358 synchronized (target.getTreeLock()) 359 { 360 Dimension dim = new Dimension(0, 0); 361 int nmembers = target.getComponentCount(); 362 boolean firstVisibleComponent = true; 363 364 for (int i = 0; i < nmembers; i++) 365 { 366 Component m = target.getComponent(i); 367 if (m.isVisible()) 368 { 369 Dimension d = m.getPreferredSize(); 370 dim.height = Math.max(dim.height, d.height); 371 if (firstVisibleComponent) 372 { 373 firstVisibleComponent = false; 374 } 375 else 376 { 377 dim.width += hgap; 378 } 379 dim.width += d.width; 380 } 381 } 382 383 Insets insets = target.getInsets(); 384 dim.width += insets.left + insets.right + hgap * 2; 385 dim.height += insets.top + insets.bottom + vgap * 2; 386 387 return (dim); 388 } 389 } 390 391 /*--------------------------------------------------------------------------*/ 392 /** 393 * Returns the minimum dimensions needed to layout the components contained in the specified 394 * target container. 395 * 396 * @param target the component which needs to be laid out 397 * 398 * @return the minimum dimensions to lay out the subcomponents of the specified container. 399 * 400 * @see #preferredLayoutSize(Container) 401 */ 402 /*--------------------------------------------------------------------------*/ 403 public Dimension minimumLayoutSize(Container target) 404 { 405 synchronized (target.getTreeLock()) 406 { 407 Dimension dim = new Dimension(0, 0); 408 int nmembers = target.getComponentCount(); 409 410 for (int i = 0; i < nmembers; i++) 411 { 412 Component m = target.getComponent(i); 413 if (m.isVisible()) 414 { 415 Dimension d = m.getMinimumSize(); 416 dim.height = Math.max(dim.height, d.height); 417 if (i > 0) 418 { 419 dim.width += hgap; 420 } 421 dim.width += d.width; 422 } 423 } 424 425 Insets insets = target.getInsets(); 426 dim.width += insets.left + insets.right + hgap * 2; 427 dim.height += insets.top + insets.bottom + vgap * 2; 428 429 return (dim); 430 } 431 } 432 433 /*--------------------------------------------------------------------------*/ 434 /** 435 * Centers the elements in the specified row, if there is any slack. 436 * 437 * @param target the component which needs to be moved 438 * @param x the x coordinate 439 * @param y the y coordinate 440 * @param width the width dimensions 441 * @param height the height dimensions 442 * @param rowStart the beginning of the row 443 * @param rowEnd the the ending of the row 444 */ 445 /*--------------------------------------------------------------------------*/ 446 private void moveComponents(Container target, int x, int y, int width, int height, 447 int rowStart, int rowEnd, boolean ltr) 448 { 449 synchronized (target.getTreeLock()) 450 { 451 switch (newAlign) 452 { 453 case LEFT: 454 x += ltr ? 0 : width; 455 break; 456 case CENTER: 457 x += width / 2; 458 break; 459 case RIGHT: 460 x += ltr ? width : 0; 461 break; 462 case LEADING: 463 break; 464 case TRAILING: 465 x += width; 466 break; 467 } 468 469 for (int i = rowStart; i < rowEnd; i++) 470 { 471 Component m = target.getComponent(i); 472 473 if (m.isVisible()) 474 { 475 if (ltr) 476 { 477 m.setLocation(x, y + (height - m.getSize().height) / 2); 478 } 479 else 480 { 481 m.setLocation(target.getSize().width - x - m.getSize().width, y 482 + (height - m.getSize().height) / 2); 483 } 484 485 x += m.getSize().width + hgap; 486 } 487 } 488 } 489 } 490 491 /*--------------------------------------------------------------------------*/ 492 /** 493 * Lays out the container. This method lets each component take its preferred size by reshaping 494 * the components in the target container in order to satisfy the constraints of this 495 * <code>FlowLayout</code> object. 496 * 497 * @param target the specified component being laid out. 498 * 499 */ 500 /*--------------------------------------------------------------------------*/ 501 public void layoutContainer(Container target) 502 { 503 synchronized (target.getTreeLock()) 504 { 505 Insets insets = target.getInsets(); 506 int maxWidth = target.getSize().width - (insets.left + insets.right + hgap * 2); 507 int nMembers = target.getComponentCount(); 508 int x = 0; 509 int y = insets.top + vgap; 510 int rowh = 0; 511 int start = 0; 512 513 boolean ltr = target.getComponentOrientation().isLeftToRight(); 514 515 for (int i = 0; i < nMembers; i++) 516 { 517 Component m = target.getComponent(i); 518 519 if (m.isVisible()) 520 { 521 Dimension d = m.getPreferredSize(); 522 m.setSize(d.width, d.height); 523 524 if ((x == 0) || ((x + d.width) <= maxWidth)) 525 { 526 if (x > 0) 527 { 528 x += hgap; 529 } 530 x += d.width; 531 rowh = Math.max(rowh, d.height); 532 } 533 else 534 { 535 moveComponents(target, insets.left, y, maxWidth - x, rowh, start, i, ltr); 536 x = d.width; 537 y += vgap + rowh; 538 rowh = d.height; 539 start = i; 540 } 541 } 542 } 543 544 moveComponents(target, insets.left, y, maxWidth - x, rowh, start, nMembers, ltr); 545 } 546 } 547 548 /*--------------------------------------------------------------------------*/ 549 /** 550 * Returns a string representation of this <code>FlowLayout</code> object and its values. 551 * 552 * @return a string representation of this layout. 553 */ 554 /*--------------------------------------------------------------------------*/ 555 public String toString() 556 { 557 String str = ""; 558 559 switch (align) 560 { 561 case LEFT: 562 str = ",align=left"; 563 break; 564 case CENTER: 565 str = ",align=center"; 566 break; 567 case RIGHT: 568 str = ",align=right"; 569 break; 570 case LEADING: 571 str = ",align=leading"; 572 break; 573 case TRAILING: 574 str = ",align=trailing"; 575 break; 576 } 577 578 return (getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + str + "]"); 579 } 580} 581/*---------------------------------------------------------------------------*/