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