1. /*
  2. * @(#)BorderLayout.java 1.41 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.util.Hashtable;
  9. /**
  10. * A border layout lays out a container, arranging and resizing
  11. * its components to fit in five regions:
  12. * north, south, east, west, and center.
  13. * Each region is identified by a corresponding constant:
  14. * <code>NORTH</code>, <code>SOUTH</code>, <code>EAST</code>,
  15. * <code>WEST</code>, and <code>CENTER</code>. When adding a
  16. * component to a container with a border layout, use one of these
  17. * five constants, for example:
  18. * <pre>
  19. * Panel p = new Panel();
  20. * p.setLayout(new BorderLayout());
  21. * p.add(new Button("Okay"), BorderLayout.SOUTH);
  22. * </pre>
  23. * As a convenience, BorderLayout interprets the absence of a string
  24. * specification the same as the constant <code>CENTER</code>:
  25. * <pre>
  26. * Panel p2 = new Panel();
  27. * p2.setLayout(new BorderLayout());
  28. * p2.add(new TextArea()); // Same as p.add(new TextArea(), BorderLayout.CENTER);
  29. * </pre>
  30. * <p>
  31. * In addition, BorderLayout supports four relative positioning constants,
  32. * <code>BEFORE_FIRST_LINE</code>, <code>AFTER_LAST_LINE</code>,
  33. * <code>BEFORE_LINE_BEGINS</code>, and <code>AFTER_LINE_ENDS</code>.
  34. * In a container whose ComponentOrientation is set to
  35. * <code>ComponentOrientation.LEFT_TO_RIGHT</code>, these constants map to
  36. * <code>NORTH</code>, <code>SOUTH</code>, <code>WEST</code>, and
  37. * <code>EAST</code>, respectively
  38. * <p>
  39. * Mixing the two types of constants can lead to unpredicable results. If
  40. * you use both types, the relative constants will take precedence.
  41. * For example, if you add components using both the <code>NORTH</code>
  42. * and <code>BEFORE_FIRST_LINE</code> constants in a container whose
  43. * orientation is <code>LEFT_TO_RIGHT</code>, only the
  44. * <code>BEFORE_FIRST_LINE</code> will be layed out.
  45. * <p>
  46. * NOTE: Currently (in JDK 1.2), BorderLayout does not support vertical
  47. * orientations. The <code>isVertical</code> setting on the container's
  48. * ComponentOrientation is not respected.
  49. * <p>
  50. * The components are laid out according to their
  51. * preferred sizes and the constraints of the container's size.
  52. * The <code>NORTH</code> and <code>SOUTH</code> components may
  53. * be stretched horizontally; the <code>EAST</code> and
  54. * <code>WEST</code> components may be stretched vertically;
  55. * the <code>CENTER</code> component may stretch both horizontally
  56. * and vertically to fill any space left over.
  57. * <p>
  58. * Here is an example of five buttons in an applet laid out using
  59. * the <code>BorderLayout</code> layout manager:
  60. * <p>
  61. * <img src="doc-files/BorderLayout-1.gif"
  62. * ALIGN=center HSPACE=10 VSPACE=7>
  63. * <p>
  64. * The code for this applet is as follows:
  65. * <p>
  66. * <hr><blockquote><pre>
  67. * import java.awt.*;
  68. * import java.applet.Applet;
  69. *
  70. * public class buttonDir extends Applet {
  71. * public void init() {
  72. * setLayout(new BorderLayout());
  73. * add(new Button("North"), BorderLayout.NORTH);
  74. * add(new Button("South"), BorderLayout.SOUTH);
  75. * add(new Button("East"), BorderLayout.EAST);
  76. * add(new Button("West"), BorderLayout.WEST);
  77. * add(new Button("Center"), BorderLayout.CENTER);
  78. * }
  79. * }
  80. * </pre></blockquote><hr>
  81. * <p>
  82. * @version 1.27 02/11/97
  83. * @author Arthur van Hoff
  84. * @see java.awt.Container.add(String, Component)
  85. * @see java.awt.ComponentOrientation
  86. * @since JDK1.0
  87. */
  88. public class BorderLayout implements LayoutManager2,
  89. java.io.Serializable {
  90. /**
  91. * Constructs a border layout with the horizontal gaps
  92. * between components.
  93. * The horizontal gap is specified by <code>hgap</code>.
  94. *
  95. * @see getHgap()
  96. * @see setHgap()
  97. *
  98. * @serial
  99. */
  100. int hgap;
  101. /**
  102. * Constructs a border layout with the vertical gaps
  103. * between components.
  104. * The vertical gap is specified by <code>vgap</code>.
  105. *
  106. * @see getVgap()
  107. * @see setVgap()
  108. * @serial
  109. */
  110. int vgap;
  111. /**
  112. * Constant to specify components location to be the
  113. * north portion of the border layout.
  114. * @serial
  115. * @see #getChild
  116. * @see #addLayoutComponent
  117. * @see #getLayoutAllignment
  118. * @see #removeLayoutComponent
  119. */
  120. Component north;
  121. /**
  122. * Constant to specify components location to be the
  123. * west portion of the border layout.
  124. * @serial
  125. * @see #getChild
  126. * @see #addLayoutComponent
  127. * @see #getLayoutAllignment
  128. * @see #removeLayoutComponent
  129. */
  130. Component west;
  131. /**
  132. * Constant to specify components location to be the
  133. * east portion of the border layout.
  134. * @serial
  135. * @see #getChild
  136. * @see #addLayoutComponent
  137. * @see #getLayoutAllignment
  138. * @see #removeLayoutComponent
  139. */
  140. Component east;
  141. /**
  142. * Constant to specify components location to be the
  143. * south portion of the border layout.
  144. * @serial
  145. * @see #getChild
  146. * @see #addLayoutComponent
  147. * @see #getLayoutAllignment
  148. * @see #removeLayoutComponent
  149. */
  150. Component south;
  151. /**
  152. * Constant to specify components location to be the
  153. * center portion of the border layout.
  154. * @serial
  155. * @see #getChild
  156. * @see #addLayoutComponent
  157. * @see #getLayoutAllignment
  158. * @see #removeLayoutComponent
  159. */
  160. Component center;
  161. /**
  162. *
  163. * A relative positioning constant, that can be used instead of
  164. * north, south, east, west or center.
  165. * mixing the two types of constants can lead to unpredicable results. If
  166. * you use both types, the relative constants will take precedence.
  167. * For example, if you add components using both the <code>NORTH</code>
  168. * and <code>BEFORE_FIRST_LINE</code> constants in a container whose
  169. * orientation is <code>LEFT_TO_RIGHT</code>, only the
  170. * <code>BEFORE_FIRST_LINE</code> will be layed out.
  171. * This will be the same for lastLine, firstItem, lastItem.
  172. * @serial
  173. */
  174. Component firstLine;
  175. /**
  176. * A relative positioning constant, that can be used instead of
  177. * north, south, east, west or center.
  178. * Please read Description for firstLine.
  179. * @serial
  180. */
  181. Component lastLine;
  182. /**
  183. * A relative positioning constant, that can be used instead of
  184. * north, south, east, west or center.
  185. * Please read Description for firstLine.
  186. * @serial
  187. */
  188. Component firstItem;
  189. /**
  190. * A relative positioning constant, that can be used instead of
  191. * north, south, east, west or center.
  192. * Please read Description for firstLine.
  193. * @serial
  194. */
  195. Component lastItem;
  196. /**
  197. * The north layout constraint (top of container).
  198. */
  199. public static final String NORTH = "North";
  200. /**
  201. * The south layout constraint (bottom of container).
  202. */
  203. public static final String SOUTH = "South";
  204. /**
  205. * The east layout constraint (right side of container).
  206. */
  207. public static final String EAST = "East";
  208. /**
  209. * The west layout constraint (left side of container).
  210. */
  211. public static final String WEST = "West";
  212. /**
  213. * The center layout constraint (middle of container).
  214. */
  215. public static final String CENTER = "Center";
  216. /**
  217. * The component comes before the first line of the layout's content.
  218. * For Western, top-to-bottom, left-to-right orientations, this is
  219. * equivalent to NORTH.
  220. *
  221. * @see java.awt.Component#getComponentOrientation
  222. * @since JDK1.2
  223. */
  224. public static final String BEFORE_FIRST_LINE = "First";
  225. /**
  226. * The component comes after the last line of the layout's content.
  227. * For Western, top-to-bottom, left-to-right orientations, this is
  228. * equivalent to SOUTH.
  229. *
  230. * @see java.awt.Component#getComponentOrientation
  231. * @since JDK1.2
  232. */
  233. public static final String AFTER_LAST_LINE = "Last";
  234. /**
  235. * The component goes at the beginning of the line direction for the
  236. * layout. For Western, top-to-bottom, left-to-right orientations,
  237. * this is equivalent to WEST.
  238. *
  239. * @see java.awt.Component#getComponentOrientation
  240. * @since JDK1.2
  241. */
  242. public static final String BEFORE_LINE_BEGINS = "Before";
  243. /**
  244. * The component goes at the end of the line direction for the
  245. * layout. For Western, top-to-bottom, left-to-right orientations,
  246. * this is equivalent to EAST.
  247. *
  248. * @see java.awt.Component#getComponentOrientation
  249. * @since JDK1.2
  250. */
  251. public static final String AFTER_LINE_ENDS = "After";
  252. /*
  253. * JDK 1.1 serialVersionUID
  254. */
  255. private static final long serialVersionUID = -8658291919501921765L;
  256. /**
  257. * Constructs a new border layout with
  258. * no gaps between components.
  259. */
  260. public BorderLayout() {
  261. this(0, 0);
  262. }
  263. /**
  264. * Constructs a border layout with the specified gaps
  265. * between components.
  266. * The horizontal gap is specified by <code>hgap</code>
  267. * and the vertical gap is specified by <code>vgap</code>.
  268. * @param hgap the horizontal gap.
  269. * @param vgap the vertical gap.
  270. */
  271. public BorderLayout(int hgap, int vgap) {
  272. this.hgap = hgap;
  273. this.vgap = vgap;
  274. }
  275. /**
  276. * Returns the horizontal gap between components.
  277. * @since JDK1.1
  278. */
  279. public int getHgap() {
  280. return hgap;
  281. }
  282. /**
  283. * Sets the horizontal gap between components.
  284. * @param hgap the horizontal gap between components
  285. * @since JDK1.1
  286. */
  287. public void setHgap(int hgap) {
  288. this.hgap = hgap;
  289. }
  290. /**
  291. * Returns the vertical gap between components.
  292. * @since JDK1.1
  293. */
  294. public int getVgap() {
  295. return vgap;
  296. }
  297. /**
  298. * Sets the vertical gap between components.
  299. * @param vgap the vertical gap between components
  300. * @since JDK1.1
  301. */
  302. public void setVgap(int vgap) {
  303. this.vgap = vgap;
  304. }
  305. /**
  306. * Adds the specified component to the layout, using the specified
  307. * constraint object. For border layouts, the constraint must be
  308. * one of the following constants: <code>NORTH</code>,
  309. * <code>SOUTH</code>, <code>EAST</code>,
  310. * <code>WEST</code>, or <code>CENTER</code>.
  311. * <p>
  312. * Most applications do not call this method directly. This method
  313. * is called when a component is added to a container using the
  314. * <code>Container.add</code> method with the same argument types.
  315. * @param comp the component to be added.
  316. * @param constraints an object that specifies how and where
  317. * the component is added to the layout.
  318. * @see java.awt.Container#add(java.awt.Component, java.lang.Object)
  319. * @exception IllegalArgumentException if the constraint object is not
  320. * a string, or if it not one of the five specified
  321. * constants.
  322. * @since JDK1.1
  323. */
  324. public void addLayoutComponent(Component comp, Object constraints) {
  325. synchronized (comp.getTreeLock()) {
  326. if ((constraints == null) || (constraints instanceof String)) {
  327. addLayoutComponent((String)constraints, comp);
  328. } else {
  329. throw new IllegalArgumentException("cannot add to layout: constraint must be a string (or null)");
  330. }
  331. }
  332. }
  333. /**
  334. * @deprecated replaced by <code>addLayoutComponent(Component, Object)</code>.
  335. */
  336. public void addLayoutComponent(String name, Component comp) {
  337. synchronized (comp.getTreeLock()) {
  338. /* Special case: treat null the same as "Center". */
  339. if (name == null) {
  340. name = "Center";
  341. }
  342. /* Assign the component to one of the known regions of the layout.
  343. */
  344. if ("Center".equals(name)) {
  345. center = comp;
  346. } else if ("North".equals(name)) {
  347. north = comp;
  348. } else if ("South".equals(name)) {
  349. south = comp;
  350. } else if ("East".equals(name)) {
  351. east = comp;
  352. } else if ("West".equals(name)) {
  353. west = comp;
  354. } else if (BEFORE_FIRST_LINE.equals(name)) {
  355. firstLine = comp;
  356. } else if (AFTER_LAST_LINE.equals(name)) {
  357. lastLine = comp;
  358. } else if (BEFORE_LINE_BEGINS.equals(name)) {
  359. firstItem = comp;
  360. } else if (AFTER_LINE_ENDS.equals(name)) {
  361. lastItem = comp;
  362. } else {
  363. throw new IllegalArgumentException("cannot add to layout: unknown constraint: " + name);
  364. }
  365. }
  366. }
  367. /**
  368. * Removes the specified component from this border layout. This
  369. * method is called when a container calls its <code>remove</code> or
  370. * <code>removeAll</code> methods. Most applications do not call this
  371. * method directly.
  372. * @param comp the component to be removed.
  373. * @see java.awt.Container#remove(java.awt.Component)
  374. * @see java.awt.Container#removeAll()
  375. */
  376. public void removeLayoutComponent(Component comp) {
  377. synchronized (comp.getTreeLock()) {
  378. if (comp == center) {
  379. center = null;
  380. } else if (comp == north) {
  381. north = null;
  382. } else if (comp == south) {
  383. south = null;
  384. } else if (comp == east) {
  385. east = null;
  386. } else if (comp == west) {
  387. west = null;
  388. }
  389. if (comp == firstLine) {
  390. firstLine = null;
  391. } else if (comp == lastLine) {
  392. lastLine = null;
  393. } else if (comp == firstItem) {
  394. firstItem = null;
  395. } else if (comp == lastItem) {
  396. lastItem = null;
  397. }
  398. }
  399. }
  400. /**
  401. * Determines the minimum size of the <code>target</code> container
  402. * using this layout manager.
  403. * <p>
  404. * This method is called when a container calls its
  405. * <code>getMinimumSize</code> method. Most applications do not call
  406. * this method directly.
  407. * @param target the container in which to do the layout.
  408. * @return the minimum dimensions needed to lay out the subcomponents
  409. * of the specified container.
  410. * @see java.awt.Container
  411. * @see java.awt.BorderLayout#preferredLayoutSize
  412. * @see java.awt.Container#getMinimumSize()
  413. */
  414. public Dimension minimumLayoutSize(Container target) {
  415. synchronized (target.getTreeLock()) {
  416. Dimension dim = new Dimension(0, 0);
  417. boolean ltr = target.getComponentOrientation().isLeftToRight();
  418. Component c = null;
  419. if ((c=getChild(EAST,ltr)) != null) {
  420. Dimension d = c.getMinimumSize();
  421. dim.width += d.width + hgap;
  422. dim.height = Math.max(d.height, dim.height);
  423. }
  424. if ((c=getChild(WEST,ltr)) != null) {
  425. Dimension d = c.getMinimumSize();
  426. dim.width += d.width + hgap;
  427. dim.height = Math.max(d.height, dim.height);
  428. }
  429. if ((c=getChild(CENTER,ltr)) != null) {
  430. Dimension d = c.getMinimumSize();
  431. dim.width += d.width;
  432. dim.height = Math.max(d.height, dim.height);
  433. }
  434. if ((c=getChild(NORTH,ltr)) != null) {
  435. Dimension d = c.getMinimumSize();
  436. dim.width = Math.max(d.width, dim.width);
  437. dim.height += d.height + vgap;
  438. }
  439. if ((c=getChild(SOUTH,ltr)) != null) {
  440. Dimension d = c.getMinimumSize();
  441. dim.width = Math.max(d.width, dim.width);
  442. dim.height += d.height + vgap;
  443. }
  444. Insets insets = target.getInsets();
  445. dim.width += insets.left + insets.right;
  446. dim.height += insets.top + insets.bottom;
  447. return dim;
  448. }
  449. }
  450. /**
  451. * Determines the preferred size of the <code>target</code>
  452. * container using this layout manager, based on the components
  453. * in the container.
  454. * <p>
  455. * Most applications do not call this method directly. This method
  456. * is called when a container calls its <code>getPreferredSize</code>
  457. * method.
  458. * @param target the container in which to do the layout.
  459. * @return the preferred dimensions to lay out the subcomponents
  460. * of the specified container.
  461. * @see java.awt.Container
  462. * @see java.awt.BorderLayout#minimumLayoutSize
  463. * @see java.awt.Container#getPreferredSize()
  464. */
  465. public Dimension preferredLayoutSize(Container target) {
  466. synchronized (target.getTreeLock()) {
  467. Dimension dim = new Dimension(0, 0);
  468. boolean ltr = target.getComponentOrientation().isLeftToRight();
  469. Component c = null;
  470. if ((c=getChild(EAST,ltr)) != null) {
  471. Dimension d = c.getPreferredSize();
  472. dim.width += d.width + hgap;
  473. dim.height = Math.max(d.height, dim.height);
  474. }
  475. if ((c=getChild(WEST,ltr)) != null) {
  476. Dimension d = c.getPreferredSize();
  477. dim.width += d.width + hgap;
  478. dim.height = Math.max(d.height, dim.height);
  479. }
  480. if ((c=getChild(CENTER,ltr)) != null) {
  481. Dimension d = c.getPreferredSize();
  482. dim.width += d.width;
  483. dim.height = Math.max(d.height, dim.height);
  484. }
  485. if ((c=getChild(NORTH,ltr)) != null) {
  486. Dimension d = c.getPreferredSize();
  487. dim.width = Math.max(d.width, dim.width);
  488. dim.height += d.height + vgap;
  489. }
  490. if ((c=getChild(SOUTH,ltr)) != null) {
  491. Dimension d = c.getPreferredSize();
  492. dim.width = Math.max(d.width, dim.width);
  493. dim.height += d.height + vgap;
  494. }
  495. Insets insets = target.getInsets();
  496. /*if[Linux]
  497. // If your insets are 0 and you have no children
  498. // then size will be 0 which will prevent a resize
  499. // from occuring so set size to 1 to enable resize
  500. // to occur on WM that allow a 0 inset
  501. dim.width += insets.left + insets.right;
  502. dim.height += insets.top + insets.bottom;
  503. if (dim.width == 0 && dim.height == 0) {
  504. dim.width=1;
  505. dim.height=1;
  506. }
  507. else[Linux]*/
  508. dim.width += insets.left + insets.right;
  509. dim.height += insets.top + insets.bottom;
  510. /*end[Linux]*/
  511. return dim;
  512. }
  513. }
  514. /**
  515. * Returns the maximum dimensions for this layout given the components
  516. * in the specified target container.
  517. * @param target the component which needs to be laid out
  518. * @see Container
  519. * @see #minimumLayoutSize
  520. * @see #preferredLayoutSize
  521. */
  522. public Dimension maximumLayoutSize(Container target) {
  523. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  524. }
  525. /**
  526. * Returns the alignment along the x axis. This specifies how
  527. * the component would like to be aligned relative to other
  528. * components. The value should be a number between 0 and 1
  529. * where 0 represents alignment along the origin, 1 is aligned
  530. * the furthest away from the origin, 0.5 is centered, etc.
  531. */
  532. public float getLayoutAlignmentX(Container parent) {
  533. return 0.5f;
  534. }
  535. /**
  536. * Returns the alignment along the y axis. This specifies how
  537. * the component would like to be aligned relative to other
  538. * components. The value should be a number between 0 and 1
  539. * where 0 represents alignment along the origin, 1 is aligned
  540. * the furthest away from the origin, 0.5 is centered, etc.
  541. */
  542. public float getLayoutAlignmentY(Container parent) {
  543. return 0.5f;
  544. }
  545. /**
  546. * Invalidates the layout, indicating that if the layout manager
  547. * has cached information it should be discarded.
  548. */
  549. public void invalidateLayout(Container target) {
  550. }
  551. /**
  552. * Lays out the container argument using this border layout.
  553. * <p>
  554. * This method actually reshapes the components in the specified
  555. * container in order to satisfy the constraints of this
  556. * <code>BorderLayout</code> object. The <code>NORTH</code>
  557. * and <code>SOUTH</code> components, if any, are placed at
  558. * the top and bottom of the container, respectively. The
  559. * <code>WEST</code> and <code>EAST</code> components are
  560. * then placed on the left and right, respectively. Finally,
  561. * the <code>CENTER</code> object is placed in any remaining
  562. * space in the middle.
  563. * <p>
  564. * Most applications do not call this method directly. This method
  565. * is called when a container calls its <code>doLayout</code> method.
  566. * @param target the container in which to do the layout.
  567. * @see java.awt.Container
  568. * @see java.awt.Container#doLayout()
  569. */
  570. public void layoutContainer(Container target) {
  571. synchronized (target.getTreeLock()) {
  572. Insets insets = target.getInsets();
  573. int top = insets.top;
  574. int bottom = target.height - insets.bottom;
  575. int left = insets.left;
  576. int right = target.width - insets.right;
  577. boolean ltr = target.getComponentOrientation().isLeftToRight();
  578. Component c = null;
  579. if ((c=getChild(NORTH,ltr)) != null) {
  580. c.setSize(right - left, c.height);
  581. Dimension d = c.getPreferredSize();
  582. c.setBounds(left, top, right - left, d.height);
  583. top += d.height + vgap;
  584. }
  585. if ((c=getChild(SOUTH,ltr)) != null) {
  586. c.setSize(right - left, c.height);
  587. Dimension d = c.getPreferredSize();
  588. c.setBounds(left, bottom - d.height, right - left, d.height);
  589. bottom -= d.height + vgap;
  590. }
  591. if ((c=getChild(EAST,ltr)) != null) {
  592. c.setSize(c.width, bottom - top);
  593. Dimension d = c.getPreferredSize();
  594. c.setBounds(right - d.width, top, d.width, bottom - top);
  595. right -= d.width + hgap;
  596. }
  597. if ((c=getChild(WEST,ltr)) != null) {
  598. c.setSize(c.width, bottom - top);
  599. Dimension d = c.getPreferredSize();
  600. c.setBounds(left, top, d.width, bottom - top);
  601. left += d.width + hgap;
  602. }
  603. if ((c=getChild(CENTER,ltr)) != null) {
  604. c.setBounds(left, top, right - left, bottom - top);
  605. }
  606. }
  607. }
  608. /**
  609. * Get the component that corresponds to the given constraint location
  610. *
  611. * @param key The desired absolute position,
  612. * either NORTH, SOUTH, EAST, or WEST.
  613. * @param ltr Is the component line direction left-to-right?
  614. */
  615. private Component getChild(String key, boolean ltr) {
  616. Component result = null;
  617. if (key == NORTH) {
  618. result = (firstLine != null) ? firstLine : north;
  619. }
  620. else if (key == SOUTH) {
  621. result = (lastLine != null) ? lastLine : south;
  622. }
  623. else if (key == WEST) {
  624. result = ltr ? firstItem : lastItem;
  625. if (result == null) {
  626. result = west;
  627. }
  628. }
  629. else if (key == EAST) {
  630. result = ltr ? lastItem : firstItem;
  631. if (result == null) {
  632. result = east;
  633. }
  634. }
  635. else if (key == CENTER) {
  636. result = center;
  637. }
  638. if (result != null && !result.visible) {
  639. result = null;
  640. }
  641. return result;
  642. }
  643. /**
  644. * Returns a string representation of the state of this border layout.
  645. * @return a string representation of this border layout.
  646. */
  647. public String toString() {
  648. return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
  649. }
  650. }