1. /*
  2. * @(#)FlowLayout.java 1.32 01/11/29
  3. *
  4. * Copyright 2002 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.32, 11/29/01
  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, e.g. to the left in left-to-right orientations.
  70. *
  71. * @see java.awt.Component#getComponentOrientation
  72. * @see java.awt.ComponentOrientation
  73. * @since JDK1.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 leading edge of the container's
  80. * orientation, e.g. to the right in left-to-right orientations.
  81. *
  82. * @see java.awt.Component#getComponentOrientation
  83. * @see java.awt.ComponentOrientation
  84. * @since JDK1.2
  85. * Package-private pending API change approval
  86. */
  87. public static final int TRAILING = 4;
  88. /**
  89. * <code>align</code> is the proprty that determines
  90. * how each row distributes empty space.
  91. * It can be one of the following three values :
  92. * <code>LEFT</code>
  93. * <code>RIGHT</code>
  94. * <code>CENTER</code>
  95. *
  96. * @serial
  97. * @see getAlignment()
  98. * @see setAlignment()
  99. */
  100. int align; // This is for 1.1 serialization compatibilitys
  101. /**
  102. * <code>newAlign</code> is the property that determines
  103. * how each row distributes empty space for JDK's >= JDK1.2.
  104. * It can be one of the following three values :
  105. * <code>LEFT</code>
  106. * <code>RIGHT</code>
  107. * <code>CENTER</code>
  108. *
  109. * @serial
  110. * @since JDK 1.2
  111. * @see getAlignment()
  112. * @see setAlignment()
  113. */
  114. int newAlign; // This is the one we actually use
  115. /**
  116. * The flow layout manager allows a seperation of
  117. * components with gaps. The horizontal gap will
  118. * specify the space between components.
  119. *
  120. * @serial
  121. * @see getHgap()
  122. * @see setHgap()
  123. */
  124. int hgap;
  125. /**
  126. * The flow layout manager allows a seperation of
  127. * components with gaps. The vertical gap will
  128. * specify the space between rows.
  129. *
  130. * @serial
  131. * @see getVgap()
  132. * @see setVgap()
  133. */
  134. int vgap;
  135. /*
  136. * JDK 1.1 serialVersionUID
  137. */
  138. private static final long serialVersionUID = -7262534875583282631L;
  139. /**
  140. * Constructs a new Flow Layout with a centered alignment and a
  141. * default 5-unit horizontal and vertical gap.
  142. */
  143. public FlowLayout() {
  144. this(CENTER, 5, 5);
  145. }
  146. /**
  147. * Constructs a new Flow Layout with the specified alignment and a
  148. * default 5-unit horizontal and vertical gap.
  149. * The value of the alignment argument must be one of
  150. * <code>FlowLayout.LEFT</code>, <code>FlowLayout.RIGHT</code>,
  151. * or <code>FlowLayout.CENTER</code>.
  152. * @param align the alignment value
  153. */
  154. public FlowLayout(int align) {
  155. this(align, 5, 5);
  156. }
  157. /**
  158. * Creates a new flow layout manager with the indicated alignment
  159. * and the indicated horizontal and vertical gaps.
  160. * <p>
  161. * The value of the alignment argument must be one of
  162. * <code>FlowLayout.LEFT</code>, <code>FlowLayout.RIGHT</code>,
  163. * or <code>FlowLayout.CENTER</code>.
  164. * @param align the alignment value.
  165. * @param hgap the horizontal gap between components.
  166. * @param vgap the vertical gap between components.
  167. */
  168. public FlowLayout(int align, int hgap, int vgap) {
  169. this.hgap = hgap;
  170. this.vgap = vgap;
  171. setAlignment(align);
  172. }
  173. /**
  174. * Gets the alignment for this layout.
  175. * Possible values are <code>FlowLayout.LEFT</code>,
  176. * <code>FlowLayout.RIGHT</code>, or <code>FlowLayout.CENTER</code>.
  177. * @return the alignment value for this layout.
  178. * @see * @see java.awt.FlowLayout#setAlignment
  179. * @since JDK1.1
  180. */
  181. public int getAlignment() {
  182. return newAlign;
  183. }
  184. /**
  185. * Sets the alignment for this layout.
  186. * Possible values are <code>FlowLayout.LEFT</code>,
  187. * <code>FlowLayout.RIGHT</code>, and <code>FlowLayout.CENTER</code>.
  188. * @param align the alignment value.
  189. * @see java.awt.FlowLayout#getAlignment
  190. * @since JDK1.1
  191. */
  192. public void setAlignment(int align) {
  193. this.newAlign = align;
  194. // this.align is used only for serialization compatibility,
  195. // so set it to a value compatible with the 1.1 version
  196. // of the class
  197. switch (align) {
  198. case LEADING:
  199. this.align = LEFT;
  200. break;
  201. case TRAILING:
  202. this.align = RIGHT;
  203. break;
  204. default:
  205. this.align = align;
  206. break;
  207. }
  208. }
  209. /**
  210. * Gets the horizontal gap between components.
  211. * @return the horizontal gap between components.
  212. * @see java.awt.FlowLayout#setHgap
  213. * @since JDK1.1
  214. */
  215. public int getHgap() {
  216. return hgap;
  217. }
  218. /**
  219. * Sets the horizontal gap between components.
  220. * @param hgap the horizontal gap between components
  221. * @see java.awt.FlowLayout#getHgap
  222. * @since JDK1.1
  223. */
  224. public void setHgap(int hgap) {
  225. this.hgap = hgap;
  226. }
  227. /**
  228. * Gets the vertical gap between components.
  229. * @return the vertical gap between components.
  230. * @see java.awt.FlowLayout#setVgap
  231. * @since JDK1.1
  232. */
  233. public int getVgap() {
  234. return vgap;
  235. }
  236. /**
  237. * Sets the vertical gap between components.
  238. * @param vgap the vertical gap between components
  239. * @see java.awt.FlowLayout#getVgap
  240. * @since JDK1.1
  241. */
  242. public void setVgap(int vgap) {
  243. this.vgap = vgap;
  244. }
  245. /**
  246. * Adds the specified component to the layout. Not used by this class.
  247. * @param name the name of the component
  248. * @param comp the component to be added
  249. */
  250. public void addLayoutComponent(String name, Component comp) {
  251. }
  252. /**
  253. * Removes the specified component from the layout. Not used by
  254. * this class.
  255. * @param comp the component to remove
  256. * @see java.awt.Container#removeAll
  257. */
  258. public void removeLayoutComponent(Component comp) {
  259. }
  260. /**
  261. * Returns the preferred dimensions for this layout given the components
  262. * in the specified target container.
  263. * @param target the component which needs to be laid out
  264. * @return the preferred dimensions to lay out the
  265. * subcomponents of the specified container.
  266. * @see Container
  267. * @see #minimumLayoutSize
  268. * @see java.awt.Container#getPreferredSize
  269. */
  270. public Dimension preferredLayoutSize(Container target) {
  271. synchronized (target.getTreeLock()) {
  272. Dimension dim = new Dimension(0, 0);
  273. int nmembers = target.getComponentCount();
  274. for (int i = 0 ; i < nmembers ; i++) {
  275. Component m = target.getComponent(i);
  276. if (m.visible) {
  277. Dimension d = m.getPreferredSize();
  278. dim.height = Math.max(dim.height, d.height);
  279. if (i > 0) {
  280. dim.width += hgap;
  281. }
  282. dim.width += d.width;
  283. }
  284. }
  285. Insets insets = target.getInsets();
  286. dim.width += insets.left + insets.right + hgap*2;
  287. dim.height += insets.top + insets.bottom + vgap*2;
  288. return dim;
  289. }
  290. }
  291. /**
  292. * Returns the minimum dimensions needed to layout the components
  293. * contained in the specified target container.
  294. * @param target the component which needs to be laid out
  295. * @return the minimum dimensions to lay out the
  296. * subcomponents of the specified container.
  297. * @see #preferredLayoutSize
  298. * @see java.awt.Container
  299. * @see java.awt.Container#doLayout
  300. */
  301. public Dimension minimumLayoutSize(Container target) {
  302. synchronized (target.getTreeLock()) {
  303. Dimension dim = new Dimension(0, 0);
  304. int nmembers = target.getComponentCount();
  305. for (int i = 0 ; i < nmembers ; i++) {
  306. Component m = target.getComponent(i);
  307. if (m.visible) {
  308. Dimension d = m.getMinimumSize();
  309. dim.height = Math.max(dim.height, d.height);
  310. if (i > 0) {
  311. dim.width += hgap;
  312. }
  313. dim.width += d.width;
  314. }
  315. }
  316. Insets insets = target.getInsets();
  317. dim.width += insets.left + insets.right + hgap*2;
  318. dim.height += insets.top + insets.bottom + vgap*2;
  319. return dim;
  320. }
  321. }
  322. /**
  323. * Centers the elements in the specified row, if there is any slack.
  324. * @param target the component which needs to be moved
  325. * @param x the x coordinate
  326. * @param y the y coordinate
  327. * @param width the width dimensions
  328. * @param height the height dimensions
  329. * @param rowStart the beginning of the row
  330. * @param rowEnd the the ending of the row
  331. */
  332. private void moveComponents(Container target, int x, int y, int width, int height,
  333. int rowStart, int rowEnd, boolean ltr) {
  334. synchronized (target.getTreeLock()) {
  335. switch (newAlign) {
  336. case LEFT:
  337. x += ltr ? 0 : width;
  338. break;
  339. case CENTER:
  340. x += width / 2;
  341. break;
  342. case RIGHT:
  343. x += ltr ? width : 0;
  344. break;
  345. case LEADING:
  346. break;
  347. case TRAILING:
  348. x += width;
  349. break;
  350. }
  351. for (int i = rowStart ; i < rowEnd ; i++) {
  352. Component m = target.getComponent(i);
  353. if (m.visible) {
  354. if (ltr) {
  355. m.setLocation(x, y + (height - m.height) / 2);
  356. } else {
  357. m.setLocation(target.width - x - m.width, y + (height - m.height) / 2);
  358. }
  359. x += m.width + hgap;
  360. }
  361. }
  362. }
  363. }
  364. /**
  365. * Lays out the container. This method lets each component take
  366. * its preferred size by reshaping the components in the
  367. * target container in order to satisfy the constraints of
  368. * this <code>FlowLayout</code> object.
  369. * @param target the specified component being laid out.
  370. * @see Container
  371. * @see java.awt.Container#doLayout
  372. */
  373. public void layoutContainer(Container target) {
  374. synchronized (target.getTreeLock()) {
  375. Insets insets = target.getInsets();
  376. int maxwidth = target.width - (insets.left + insets.right + hgap*2);
  377. int nmembers = target.getComponentCount();
  378. int x = 0, y = insets.top + vgap;
  379. int rowh = 0, start = 0;
  380. boolean ltr = target.getComponentOrientation().isLeftToRight();
  381. for (int i = 0 ; i < nmembers ; i++) {
  382. Component m = target.getComponent(i);
  383. if (m.visible) {
  384. Dimension d = m.getPreferredSize();
  385. m.setSize(d.width, d.height);
  386. if ((x == 0) || ((x + d.width) <= maxwidth)) {
  387. if (x > 0) {
  388. x += hgap;
  389. }
  390. x += d.width;
  391. rowh = Math.max(rowh, d.height);
  392. } else {
  393. moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, i, ltr);
  394. x = d.width;
  395. y += vgap + rowh;
  396. rowh = d.height;
  397. start = i;
  398. }
  399. }
  400. }
  401. moveComponents(target, insets.left + hgap, y, maxwidth - x, rowh, start, nmembers, ltr);
  402. }
  403. }
  404. //
  405. // the internal serial version which says which version was written
  406. // - 0 (default) for versions before JDK 1.2
  407. // - 1 for version >= JDK 1.2, which includes "newAlign" field
  408. //
  409. private static final int currentSerialVersion = 1;
  410. /**
  411. * This represent the <code>currentSerialVersion</code>
  412. * which is bein used. It will be one of two values :
  413. * <code>0</code> versions before JDK 1.2.
  414. * <code>1</code> versions after JDK 1.2.
  415. *
  416. * @serial
  417. * @since JDK 1.2
  418. */
  419. private int serialVersionOnStream = currentSerialVersion;
  420. /**
  421. * Read this object out of a serialization stream, handling
  422. * objects written by older versions of the class that didn't contain all
  423. * of the fields we use now..
  424. */
  425. private void readObject(ObjectInputStream stream)
  426. throws IOException, ClassNotFoundException
  427. {
  428. stream.defaultReadObject();
  429. if (serialVersionOnStream < 1) {
  430. // "newAlign" field wasn't present, so use the old "align" field.
  431. setAlignment(this.align);
  432. }
  433. serialVersionOnStream = currentSerialVersion;
  434. }
  435. /**
  436. * Returns a string representation of this <code>FlowLayout</code>
  437. * object and its values.
  438. * @return a string representation of this layout.
  439. */
  440. public String toString() {
  441. String str = "";
  442. switch (align) {
  443. case LEFT: str = ",align=left"; break;
  444. case CENTER: str = ",align=center"; break;
  445. case RIGHT: str = ",align=right"; break;
  446. case LEADING: str = ",align=leading"; break;
  447. case TRAILING: str = ",align=trailing"; break;
  448. }
  449. return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + str + "]";
  450. }
  451. }