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