1. /*
  2. * @(#)BoxLayout.java 1.21 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 javax.swing;
  8. import java.awt.*;
  9. import java.io.Serializable;
  10. import java.io.PrintStream;
  11. /**
  12. * A layout manager that allows multiple components to be layed out either
  13. * vertically or horizontally. The components will not wrap so, for
  14. * example, a vertical arrangement of components will stay vertically
  15. * arranged when the frame is resized.
  16. * <TABLE ALIGN="RIGHT" BORDER="0">
  17. * <TR>
  18. * <TD ALIGN="CENTER">
  19. * <P ALIGN="CENTER"><IMG SRC="doc-files/BoxLayout-1.gif" WIDTH="191" HEIGHT="201" ALIGN="BOTTOM" BORDER="0">
  20. * </TD>
  21. * </TR>
  22. * </TABLE>
  23. * <p>
  24. * Nesting multiple panels with different combinations of horizontal and
  25. * vertical gives an effect similar to GridBagLayout, without the
  26. * complexity. The diagram shows two panels arranged horizontally, each
  27. * of which contains 3 components arranged vertically.
  28. * <p>
  29. * The Box container uses BoxLayout (unlike JPanel, which defaults to flow
  30. * layout). You can nest multiple boxes and add components to them to get
  31. * the arrangement you want.
  32. * <p>
  33. * The BoxLayout manager that places each of its managed components
  34. * from left to right or from top to bottom.
  35. * When you create a BoxLayout, you specify whether its major axis is
  36. * the X axis (which means left to right placement) or Y axis (top to
  37. * bottom placement). Components are arranged from left to right (or
  38. * top to bottom), in the same order as they were added to the container.
  39. * <p>
  40. * Instead of using BoxLayout directly, many programs use the Box class.
  41. * The Box class provides a lightweight container that uses a BoxLayout.
  42. * Box also provides handy methods to help you use BoxLayout well.
  43. * <p>
  44. * BoxLayout attempts to arrange components
  45. * at their preferred widths (for left to right layout)
  46. * or heights (for top to bottom layout).
  47. * For a left to right layout,
  48. * if not all the components are the same height,
  49. * BoxLayout attempts to make all the components
  50. * as high as the highest component.
  51. * If that's not possible for a particular component,
  52. * then BoxLayout aligns that component vertically,
  53. * according to the component's Y alignment.
  54. * By default, a component has an Y alignment of 0.5,
  55. * which means that the vertical center of the component
  56. * should have the same Y coordinate as
  57. * the vertical centers of other components with 0.5 Y alignment.
  58. * <p>
  59. * Similarly, for a vertical layout,
  60. * BoxLayout attempts to make all components in the column
  61. * as wide as the widest component;
  62. * if that fails, it aligns them horizontally
  63. * according to their X alignments.
  64. * <p>
  65. * <strong>Warning:</strong>
  66. * Serialized objects of this class will not be compatible with
  67. * future Swing releases. The current serialization support is appropriate
  68. * for short term storage or RMI between applications running the same
  69. * version of Swing. A future release of Swing will provide support for
  70. * long term persistence.
  71. *
  72. * @see Box
  73. * @see Component#getAlignmentX
  74. * @see Component#getAlignmentY
  75. *
  76. * @author Timothy Prinzing
  77. * @version 1.21 11/29/01
  78. */
  79. public class BoxLayout implements LayoutManager2, Serializable {
  80. /**
  81. * Specifies that components should be laid out left to right.
  82. */
  83. public static final int X_AXIS = 0;
  84. /**
  85. * Specifies that components should be laid out top to buttom.
  86. */
  87. public static final int Y_AXIS = 1;
  88. /**
  89. * Creates a layout manager that will lay out components either
  90. * left to right or
  91. * top to bottom,
  92. * as specified in the <code>axis</code> parameter.
  93. *
  94. * @param target the container that needs to be laid out
  95. * @param axis the axis to lay out components along.
  96. * For left-to-right layout,
  97. * specify <code>BoxLayout.X_AXIS</code>
  98. * for top-to-bottom layout,
  99. * specify <code>BoxLayout.Y_AXIS</code>
  100. *
  101. * @exception AWTError if the value of <code>axis</code> is invalid
  102. */
  103. public BoxLayout(Container target, int axis) {
  104. if (axis != X_AXIS && axis != Y_AXIS) {
  105. throw new AWTError("Invalid axis");
  106. }
  107. this.axis = axis;
  108. this.target = target;
  109. }
  110. /**
  111. * Constructs a BoxLayout that
  112. * produces debugging messages.
  113. *
  114. * @param target the container that needs to be laid out
  115. * @param axis the axis to lay out components along; can be either
  116. * <code>BoxLayout.X_AXIS</code>
  117. * or <code>BoxLayout.Y_AXIS</code>
  118. * @param dbg the stream to which debugging messages should be sent,
  119. * null if none
  120. */
  121. BoxLayout(Container target, int axis, PrintStream dbg) {
  122. this(target, axis);
  123. this.dbg = dbg;
  124. }
  125. /**
  126. * Indicates that a child has changed its layout related information,
  127. * and thus any cached calculations should be flushed.
  128. *
  129. * @param target the affected container
  130. *
  131. * @exception AWTError if the target isn't the container specified to the
  132. * BoxLayout constructor
  133. */
  134. public void invalidateLayout(Container target) {
  135. checkContainer(target);
  136. xChildren = null;
  137. yChildren = null;
  138. xTotal = null;
  139. yTotal = null;
  140. }
  141. /**
  142. * Not used by this class.
  143. *
  144. * @param name the name of the component
  145. * @param comp the component
  146. */
  147. public void addLayoutComponent(String name, Component comp) {
  148. }
  149. /**
  150. * Not used by this class.
  151. *
  152. * @param comp the component
  153. */
  154. public void removeLayoutComponent(Component comp) {
  155. }
  156. /**
  157. * Not used by this class.
  158. *
  159. * @param comp the component
  160. * @param constraints constraints
  161. */
  162. public void addLayoutComponent(Component comp, Object constraints) {
  163. }
  164. /**
  165. * Returns the preferred dimensions for this layout, given the components
  166. * in the specified target container.
  167. *
  168. * @param target the container that needs to be laid out
  169. * @return the dimensions >= 0 && <= Integer.MAX_VALUE
  170. * @exception AWTError if the target isn't the container specified to the
  171. * BoxLayout constructor
  172. * @see Container
  173. * @see #minimumLayoutSize
  174. * @see #maximumLayoutSize
  175. */
  176. public Dimension preferredLayoutSize(Container target) {
  177. checkContainer(target);
  178. checkRequests();
  179. Dimension size = new Dimension(xTotal.preferred, yTotal.preferred);
  180. Insets insets = target.getInsets();
  181. size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
  182. size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
  183. return size;
  184. }
  185. /**
  186. * Returns the minimum dimensions needed to lay out the components
  187. * contained in the specified target container.
  188. *
  189. * @param target the container that needs to be laid out
  190. * @return the dimensions >= 0 && <= Integer.MAX_VALUE
  191. * @exception AWTError if the target isn't the container specified to the
  192. * BoxLayout constructor
  193. * @see #preferredLayoutSize
  194. * @see #maximumLayoutSize
  195. */
  196. public Dimension minimumLayoutSize(Container target) {
  197. checkContainer(target);
  198. checkRequests();
  199. Dimension size = new Dimension(xTotal.minimum, yTotal.minimum);
  200. Insets insets = target.getInsets();
  201. size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
  202. size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
  203. return size;
  204. }
  205. /**
  206. * Returns the maximum dimensions the target container can use
  207. * to lay out the components it contains.
  208. *
  209. * @param target the container that needs to be laid out
  210. * @return the dimenions >= 0 && <= Integer.MAX_VALUE
  211. * @exception AWTError if the target isn't the container specified to the
  212. * BoxLayout constructor
  213. * @see #preferredLayoutSize
  214. * @see #minimumLayoutSize
  215. */
  216. public Dimension maximumLayoutSize(Container target) {
  217. checkContainer(target);
  218. checkRequests();
  219. Dimension size = new Dimension(xTotal.maximum, yTotal.maximum);
  220. Insets insets = target.getInsets();
  221. size.width = (int) Math.min((long) size.width + (long) insets.left + (long) insets.right, Integer.MAX_VALUE);
  222. size.height = (int) Math.min((long) size.height + (long) insets.top + (long) insets.bottom, Integer.MAX_VALUE);
  223. return size;
  224. }
  225. /**
  226. * Returns the alignment along the X axis for the container.
  227. * If the box is horizontal, the default
  228. * alignment will be returned. Otherwise, the alignment needed
  229. * to place the children along the X axis will be returned.
  230. *
  231. * @param target the container
  232. * @return the alignment >= 0.0f && <= 1.0f
  233. * @exception AWTError if the target isn't the container specified to the
  234. * BoxLayout constructor
  235. */
  236. public float getLayoutAlignmentX(Container target) {
  237. checkContainer(target);
  238. checkRequests();
  239. return xTotal.alignment;
  240. }
  241. /**
  242. * Returns the alignment along the Y axis for the container.
  243. * If the box is vertical, the default
  244. * alignment will be returned. Otherwise, the alignment needed
  245. * to place the children along the Y axis will be returned.
  246. *
  247. * @param target the container
  248. * @return the alignment >= 0.0f && <= 1.0f
  249. * @exception AWTError if the target isn't the container specified to the
  250. * BoxLayout constructor
  251. */
  252. public float getLayoutAlignmentY(Container target) {
  253. checkContainer(target);
  254. checkRequests();
  255. return yTotal.alignment;
  256. }
  257. /**
  258. * Called by the AWT <!-- XXX CHECK! --> when the specified container
  259. * needs to be laid out.
  260. *
  261. * @param target the container to lay out
  262. *
  263. * @exception AWTError if the target isn't the container specified to the
  264. * BoxLayout constructor
  265. */
  266. public void layoutContainer(Container target) {
  267. checkContainer(target);
  268. checkRequests();
  269. int nChildren = target.getComponentCount();
  270. int[] xOffsets = new int[nChildren];
  271. int[] xSpans = new int[nChildren];
  272. int[] yOffsets = new int[nChildren];
  273. int[] ySpans = new int[nChildren];
  274. // determine the child placements
  275. Dimension alloc = target.getSize();
  276. Insets in = target.getInsets();
  277. alloc.width -= in.left + in.right;
  278. alloc.height -= in.top + in.bottom;
  279. if (axis == X_AXIS) {
  280. SizeRequirements.calculateTiledPositions(alloc.width, xTotal,
  281. xChildren, xOffsets,
  282. xSpans);
  283. SizeRequirements.calculateAlignedPositions(alloc.height, yTotal,
  284. yChildren, yOffsets,
  285. ySpans);
  286. } else {
  287. SizeRequirements.calculateAlignedPositions(alloc.width, xTotal,
  288. xChildren, xOffsets,
  289. xSpans);
  290. SizeRequirements.calculateTiledPositions(alloc.height, yTotal,
  291. yChildren, yOffsets,
  292. ySpans);
  293. }
  294. // flush changes to the container
  295. for (int i = 0; i < nChildren; i++) {
  296. Component c = target.getComponent(i);
  297. c.setBounds((int) Math.min((long) in.left + (long) xOffsets[i], Integer.MAX_VALUE),
  298. (int) Math.min((long) in.top + (long) yOffsets[i], Integer.MAX_VALUE),
  299. xSpans[i], ySpans[i]);
  300. }
  301. if (dbg != null) {
  302. for (int i = 0; i < nChildren; i++) {
  303. Component c = target.getComponent(i);
  304. dbg.println(c.toString());
  305. dbg.println("X: " + xChildren[i]);
  306. dbg.println("Y: " + yChildren[i]);
  307. }
  308. }
  309. }
  310. void checkContainer(Container target) {
  311. if (this.target != target) {
  312. throw new AWTError("BoxLayout can't be shared");
  313. }
  314. }
  315. void checkRequests() {
  316. if (xChildren == null || yChildren == null) {
  317. // The requests have been invalidated... recalculate
  318. // the request information.
  319. int n = target.getComponentCount();
  320. xChildren = new SizeRequirements[n];
  321. yChildren = new SizeRequirements[n];
  322. for (int i = 0; i < n; i++) {
  323. Component c = target.getComponent(i);
  324. Dimension min = c.getMinimumSize();
  325. Dimension typ = c.getPreferredSize();
  326. Dimension max = c.getMaximumSize();
  327. xChildren[i] = new SizeRequirements(min.width, typ.width,
  328. max.width,
  329. c.getAlignmentX());
  330. yChildren[i] = new SizeRequirements(min.height, typ.height,
  331. max.height,
  332. c.getAlignmentY());
  333. }
  334. if (axis == X_AXIS) {
  335. xTotal = SizeRequirements.getTiledSizeRequirements(xChildren);
  336. yTotal = SizeRequirements.getAlignedSizeRequirements(yChildren);
  337. } else {
  338. xTotal = SizeRequirements.getAlignedSizeRequirements(xChildren);
  339. yTotal = SizeRequirements.getTiledSizeRequirements(yChildren);
  340. }
  341. }
  342. }
  343. private int axis;
  344. private Container target;
  345. private transient SizeRequirements[] xChildren;
  346. private transient SizeRequirements[] yChildren;
  347. private transient SizeRequirements xTotal;
  348. private transient SizeRequirements yTotal;
  349. private transient PrintStream dbg;
  350. }