1. /*
  2. * @(#)FlowLayout.java 1.52 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt;
  8. import java.io.ObjectInputStream;
  9. import java.io.IOException;
  10. /**
  11. * A flow layout arranges components in a directional flow, much
  12. * like lines of text in a paragraph. The flow direction is
  13. * determined by the container's <code>componentOrientation</code>
  14. * property and may be one of two values:
  15. * <ul>
  16. * <li><code>ComponentOrientation.LEFT_TO_RIGHT</code>
  17. * <li><code>ComponentOrientation.RIGHT_TO_LEFT</code>
  18. * </ul>
  19. * Flow layouts are typically used
  20. * to arrange buttons in a panel. It arranges buttons
  21. * horizontally until no more buttons fit on the same line.
  22. * The line alignment is determined by the <code>align</code>
  23. * property. The possible values are:
  24. * <ul>
  25. * <li>{@link #LEFT LEFT}
  26. * <li>{@link #RIGHT RIGHT}
  27. * <li>{@link #CENTER CENTER}
  28. * <li>{@link #LEADING LEADING}
  29. * <li>{@link #TRAILING TRAILING}
  30. * </ul>
  31. * <p>
  32. * For example, the following picture shows an applet using the flow
  33. * layout manager (its default layout manager) to position three buttons:
  34. * <p>
  35. * <img src="doc-files/FlowLayout-1.gif"
  36. * ALT="Graphic of Layout for Three Buttons"
  37. * ALIGN=center HSPACE=10 VSPACE=7>
  38. * <p>
  39. * Here is the code for this applet:
  40. * <p>
  41. * <hr><blockquote><pre>
  42. * import java.awt.*;
  43. * import java.applet.Applet;
  44. *
  45. * public class myButtons extends Applet {
  46. * Button button1, button2, button3;
  47. * public void init() {
  48. * button1 = new Button("Ok");
  49. * button2 = new Button("Open");
  50. * button3 = new Button("Close");
  51. * add(button1);
  52. * add(button2);
  53. * add(button3);
  54. * }
  55. * }
  56. * </pre></blockquote><hr>
  57. * <p>
  58. * A flow layout lets each component assume its natural (preferred) size.
  59. *
  60. * @version 1.52, 12/19/03
  61. * @author Arthur van Hoff
  62. * @author Sami Shaio
  63. * @since JDK1.0
  64. * @see ComponentOrientation
  65. */
  66. public class FlowLayout implements LayoutManager, java.io.Serializable {
  67. /**
  68. * This value indicates that each row of components
  69. * should be left-justified.
  70. */
  71. public static final int LEFT = 0;
  72. /**
  73. * This value indicates that each row of components
  74. * should be centered.
  75. */
  76. public static final int CENTER = 1;
  77. /**
  78. * This value indicates that each row of components
  79. * should be right-justified.
  80. */
  81. public static final int RIGHT = 2;
  82. /**
  83. * This value indicates that each row of components
  84. * should be justified to the leading edge of the container's
  85. * orientation, for example, to the left in left-to-right orientations.
  86. *
  87. * @see java.awt.Component#getComponentOrientation
  88. * @see java.awt.ComponentOrientation
  89. * @since 1.2
  90. * Package-private pending API change approval
  91. */
  92. public static final int LEADING = 3;
  93. /**
  94. * This value indicates that each row of components
  95. * should be justified to the trailing edge of the container's
  96. * orientation, for example, to the right in left-to-right orientations.
  97. *
  98. * @see java.awt.Component#getComponentOrientation
  99. * @see java.awt.ComponentOrientation
  100. * @since 1.2
  101. * Package-private pending API change approval
  102. */
  103. public static final int TRAILING = 4;
  104. /**
  105. * <code>align</code> is the property that determines
  106. * how each row distributes empty space.
  107. * It can be one of the following values:
  108. * <ul>
  109. * <code>LEFT</code>
  110. * <code>RIGHT</code>
  111. * <code>CENTER</code>
  112. * <code>LEADING</code>
  113. * <code>TRAILING</code>
  114. * </ul>
  115. *
  116. * @serial
  117. * @see #getAlignment
  118. * @see #setAlignment
  119. */
  120. int align; // This is for 1.1 serialization compatibility
  121. /**
  122. * <code>newAlign</code> is the property that determines
  123. * how each row distributes empty space for the Java 2 platform,
  124. * v1.2 and greater.
  125. * It can be one of the following three values:
  126. * <ul>
  127. * <code>LEFT</code>
  128. * <code>RIGHT</code>
  129. * <code>CENTER</code>
  130. * <code>LEADING</code>
  131. * <code>TRAILING</code>
  132. * </ul>
  133. *
  134. * @serial
  135. * @since 1.2
  136. * @see #getAlignment
  137. * @see #setAlignment
  138. */
  139. int newAlign; // This is the one we actually use
  140. /**
  141. * The flow layout manager allows a seperation of
  142. * components with gaps. The horizontal gap will
  143. * specify the space between components and between
  144. * the components and the borders of the
  145. * <code>Container</code>.
  146. *
  147. * @serial
  148. * @see #getHgap()
  149. * @see #setHgap(int)
  150. */
  151. int hgap;
  152. /**
  153. * The flow layout manager allows a seperation of
  154. * components with gaps. The vertical gap will
  155. * specify the space between rows and between the
  156. * the rows and the borders of the <code>Container</code>.
  157. *
  158. * @serial
  159. * @see #getHgap()
  160. * @see #setHgap(int)
  161. */
  162. int vgap;
  163. /*
  164. * JDK 1.1 serialVersionUID
  165. */
  166. private static final long serialVersionUID = -7262534875583282631L;
  167. /**
  168. * Constructs a new <code>FlowLayout</code> with a centered alignment and a
  169. * default 5-unit horizontal and vertical gap.
  170. */
  171. public FlowLayout() {
  172. this(CENTER, 5, 5);
  173. }
  174. /**
  175. * Constructs a new <code>FlowLayout</code> with the specified
  176. * alignment and a default 5-unit horizontal and vertical gap.
  177. * The value of the alignment argument must be one of
  178. * <code>FlowLayout.LEFT</code>, <code>FlowLayout.RIGHT</code>,
  179. * <code>FlowLayout.CENTER</code>, <code>FlowLayout.LEADING</code>,
  180. * or <code>FlowLayout.TRAILING</code>.
  181. * @param align the alignment value
  182. */
  183. public FlowLayout(int align) {
  184. this(align, 5, 5);
  185. }
  186. /**
  187. * Creates a new flow layout manager with the indicated alignment
  188. * and the indicated horizontal and vertical gaps.
  189. * <p>
  190. * The value of the alignment argument must be one of
  191. * <code>FlowLayout.LEFT</code>, <code>FlowLayout.RIGHT</code>,
  192. * <code>FlowLayout.CENTER</code>, <code>FlowLayout.LEADING</code>,
  193. * or <code>FlowLayout.TRAILING</code>.
  194. * @param align the alignment value
  195. * @param hgap the horizontal gap between components
  196. * and between the components and the
  197. * borders of the <code>Container</code>
  198. * @param vgap the vertical gap between components
  199. * and between the components and the
  200. * borders of the <code>Container</code>
  201. */
  202. public FlowLayout(int align, int hgap, int vgap) {
  203. this.hgap = hgap;
  204. this.vgap = vgap;
  205. setAlignment(align);
  206. }
  207. /**
  208. * Gets the alignment for this layout.
  209. * Possible values are <code>FlowLayout.LEFT</code>,
  210. * <code>FlowLayout.RIGHT</code>, <code>FlowLayout.CENTER</code>,
  211. * <code>FlowLayout.LEADING</code>,
  212. * or <code>FlowLayout.TRAILING</code>.
  213. * @return the alignment value for this layout
  214. * @see java.awt.FlowLayout#setAlignment
  215. * @since JDK1.1
  216. */
  217. public int getAlignment() {
  218. return newAlign;
  219. }
  220. /**
  221. * Sets the alignment for this layout.
  222. * Possible values are
  223. * <ul>
  224. * <li><code>FlowLayout.LEFT</code>
  225. * <li><code>FlowLayout.RIGHT</code>
  226. * <li><code>FlowLayout.CENTER</code>
  227. * <li><code>FlowLayout.LEADING</code>
  228. * <li><code>FlowLayout.TRAILING</code>
  229. * </ul>
  230. * @param align one of the alignment values shown above
  231. * @see #getAlignment()
  232. * @since JDK1.1
  233. */
  234. public void setAlignment(int align) {
  235. this.newAlign = align;
  236. // this.align is used only for serialization compatibility,
  237. // so set it to a value compatible with the 1.1 version
  238. // of the class
  239. switch (align) {
  240. case LEADING:
  241. this.align = LEFT;
  242. break;
  243. case TRAILING:
  244. this.align = RIGHT;
  245. break;
  246. default:
  247. this.align = align;
  248. break;
  249. }
  250. }
  251. /**
  252. * Gets the horizontal gap between components
  253. * and between the components and the borders
  254. * of the <code>Container</code>
  255. *
  256. * @return the horizontal gap between components
  257. * and between the components and the borders
  258. * of the <code>Container</code>
  259. * @see java.awt.FlowLayout#setHgap
  260. * @since JDK1.1
  261. */
  262. public int getHgap() {
  263. return hgap;
  264. }
  265. /**
  266. * Sets the horizontal gap between components and
  267. * between the components and the borders of the
  268. * <code>Container</code>.
  269. *
  270. * @param hgap the horizontal gap between components
  271. * and between the components and the borders
  272. * of the <code>Container</code>
  273. * @see java.awt.FlowLayout#getHgap
  274. * @since JDK1.1
  275. */
  276. public void setHgap(int hgap) {
  277. this.hgap = hgap;
  278. }
  279. /**
  280. * Gets the vertical gap between components and
  281. * between the components and the borders of the
  282. * <code>Container</code>.
  283. *
  284. * @return the vertical gap between components
  285. * and between the components and the borders
  286. * of the <code>Container</code>
  287. * @see java.awt.FlowLayout#setVgap
  288. * @since JDK1.1
  289. */
  290. public int getVgap() {
  291. return vgap;
  292. }
  293. /**
  294. * Sets the vertical gap between components and between
  295. * the components and the borders of the <code>Container</code>.
  296. *
  297. * @param vgap the vertical gap between components
  298. * and between the components and the borders
  299. * of the <code>Container</code>
  300. * @see java.awt.FlowLayout#getVgap
  301. * @since JDK1.1
  302. */
  303. public void setVgap(int vgap) {
  304. this.vgap = vgap;
  305. }
  306. /**
  307. * Adds the specified component to the layout.
  308. * Not used by this class.
  309. * @param name the name of the component
  310. * @param comp the component to be added
  311. */
  312. public void addLayoutComponent(String name, Component comp) {
  313. }
  314. /**
  315. * Removes the specified component from the layout.
  316. * Not used by this class.
  317. * @param comp the component to remove
  318. * @see java.awt.Container#removeAll
  319. */
  320. public void removeLayoutComponent(Component comp) {
  321. }
  322. /**
  323. * Returns the preferred dimensions for this layout given the
  324. * <i>visible</i> components in the specified target container.
  325. *
  326. * @param target the container that needs to be laid out
  327. * @return the preferred dimensions to lay out the
  328. * subcomponents of the specified container
  329. * @see Container
  330. * @see #minimumLayoutSize
  331. * @see java.awt.Container#getPreferredSize
  332. */
  333. public Dimension preferredLayoutSize(Container target) {
  334. synchronized (target.getTreeLock()) {
  335. Dimension dim = new Dimension(0, 0);
  336. int nmembers = target.getComponentCount();
  337. boolean firstVisibleComponent = true;
  338. for (int i = 0 ; i < nmembers ; i++) {
  339. Component m = target.getComponent(i);
  340. if (m.visible) {
  341. Dimension d = m.getPreferredSize();
  342. dim.height = Math.max(dim.height, d.height);
  343. if (firstVisibleComponent) {
  344. firstVisibleComponent = false;
  345. } else {
  346. dim.width += hgap;
  347. }
  348. dim.width += d.width;
  349. }
  350. }
  351. Insets insets = target.getInsets();
  352. dim.width += insets.left + insets.right + hgap*2;
  353. dim.height += insets.top + insets.bottom + vgap*2;
  354. return dim;
  355. }
  356. }
  357. /**
  358. * Returns the minimum dimensions needed to layout the <i>visible</i>
  359. * components contained in the specified target container.
  360. * @param target the container that needs to be laid out
  361. * @return the minimum dimensions to lay out the
  362. * subcomponents of the specified container
  363. * @see #preferredLayoutSize
  364. * @see java.awt.Container
  365. * @see java.awt.Container#doLayout
  366. */
  367. public Dimension minimumLayoutSize(Container target) {
  368. synchronized (target.getTreeLock()) {
  369. Dimension dim = new Dimension(0, 0);
  370. int nmembers = target.getComponentCount();
  371. for (int i = 0 ; i < nmembers ; i++) {
  372. Component m = target.getComponent(i);
  373. if (m.visible) {
  374. Dimension d = m.getMinimumSize();
  375. dim.height = Math.max(dim.height, d.height);
  376. if (i > 0) {
  377. dim.width += hgap;
  378. }
  379. dim.width += d.width;
  380. }
  381. }
  382. Insets insets = target.getInsets();
  383. dim.width += insets.left + insets.right + hgap*2;
  384. dim.height += insets.top + insets.bottom + vgap*2;
  385. return dim;
  386. }
  387. }
  388. /**
  389. * Centers the elements in the specified row, if there is any slack.
  390. * @param target the component which needs to be moved
  391. * @param x the x coordinate
  392. * @param y the y coordinate
  393. * @param width the width dimensions
  394. * @param height the height dimensions
  395. * @param rowStart the beginning of the row
  396. * @param rowEnd the the ending of the row
  397. */
  398. private void moveComponents(Container target, int x, int y, int width, int height,
  399. int rowStart, int rowEnd, boolean ltr) {
  400. synchronized (target.getTreeLock()) {
  401. switch (newAlign) {
  402. case LEFT:
  403. x += ltr ? 0 : width;
  404. break;
  405. case CENTER:
  406. x += width / 2;
  407. break;
  408. case RIGHT:
  409. x += ltr ? width : 0;
  410. break;
  411. case LEADING:
  412. break;
  413. case TRAILING:
  414. x += width;
  415. break;
  416. }
  417. for (int i = rowStart ; i < rowEnd ; i++) {
  418. Component m = target.getComponent(i);
  419. if (m.visible) {
  420. if (ltr) {
  421. m.setLocation(x, y + (height - m.height) / 2);
  422. } else {
  423. m.setLocation(target.width - x - m.width, y + (height - m.height) / 2);
  424. }
  425. x += m.width + hgap;
  426. }
  427. }
  428. }
  429. }
  430. /**
  431. * Lays out the container. This method lets each
  432. * <i>visible</i> component take
  433. * its preferred size by reshaping the components in the
  434. * target container in order to satisfy the alignment of
  435. * this <code>FlowLayout</code> object.
  436. *
  437. * @param target the specified component being laid out
  438. * @see Container
  439. * @see java.awt.Container#doLayout
  440. */
  441. public void layoutContainer(Container target) {
  442. synchronized (target.getTreeLock()) {
  443. Insets insets = target.getInsets();
  444. int maxwidth = target.width - (insets.left + insets.right + hgap*2);
  445. int nmembers = target.getComponentCount();
  446. int x = 0, y = insets.top + vgap;
  447. int rowh = 0, start = 0;
  448. boolean ltr = target.getComponentOrientation().isLeftToRight();
  449. for (int i = 0 ; i < nmembers ; i++) {
  450. Component m = target.getComponent(i);
  451. if (m.visible) {
  452. Dimension d = m.getPreferredSize();
  453. m.setSize(d.width, d.height);
  454. if ((x == 0) || ((x + d.width) <= maxwidth)) {
  455. if (x > 0) {
  456. x += hgap;
  457. }
  458. x += d.width;
  459. rowh = Math.max(rowh, d.height);
  460. } else {
  461. moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, i, ltr);
  462. x = d.width;
  463. y += vgap + rowh;
  464. rowh = d.height;
  465. start = i;
  466. }
  467. }
  468. }
  469. moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, nmembers, ltr);
  470. }
  471. }
  472. //
  473. // the internal serial version which says which version was written
  474. // - 0 (default) for versions before the Java 2 platform, v1.2
  475. // - 1 for version >= Java 2 platform v1.2, which includes "newAlign" field
  476. //
  477. private static final int currentSerialVersion = 1;
  478. /**
  479. * This represent the <code>currentSerialVersion</code>
  480. * which is bein used. It will be one of two values :
  481. * <code>0</code> versions before Java 2 platform v1.2..
  482. * <code>1</code> versions after Java 2 platform v1.2..
  483. *
  484. * @serial
  485. * @since 1.2
  486. */
  487. private int serialVersionOnStream = currentSerialVersion;
  488. /**
  489. * Reads this object out of a serialization stream, handling
  490. * objects written by older versions of the class that didn't contain all
  491. * of the fields we use now..
  492. */
  493. private void readObject(ObjectInputStream stream)
  494. throws IOException, ClassNotFoundException
  495. {
  496. stream.defaultReadObject();
  497. if (serialVersionOnStream < 1) {
  498. // "newAlign" field wasn't present, so use the old "align" field.
  499. setAlignment(this.align);
  500. }
  501. serialVersionOnStream = currentSerialVersion;
  502. }
  503. /**
  504. * Returns a string representation of this <code>FlowLayout</code>
  505. * object and its values.
  506. * @return a string representation of this layout
  507. */
  508. public String toString() {
  509. String str = "";
  510. switch (align) {
  511. case LEFT: str = ",align=left"; break;
  512. case CENTER: str = ",align=center"; break;
  513. case RIGHT: str = ",align=right"; break;
  514. case LEADING: str = ",align=leading"; break;
  515. case TRAILING: str = ",align=trailing"; break;
  516. }
  517. return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + str + "]";
  518. }
  519. }