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