1. /*
  2. * @(#)GridBagLayout.java 1.35 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. import java.util.Vector;
  10. class GridBagLayoutInfo implements java.io.Serializable {
  11. int width, height; /* number of cells horizontally, vertically */
  12. int startx, starty; /* starting point for layout */
  13. int minWidth[]; /* largest minWidth in each column */
  14. int minHeight[]; /* largest minHeight in each row */
  15. double weightX[]; /* largest weight in each column */
  16. double weightY[]; /* largest weight in each row */
  17. GridBagLayoutInfo () {
  18. minWidth = new int[GridBagLayout.MAXGRIDSIZE];
  19. minHeight = new int[GridBagLayout.MAXGRIDSIZE];
  20. weightX = new double[GridBagLayout.MAXGRIDSIZE];
  21. weightY = new double[GridBagLayout.MAXGRIDSIZE];
  22. }
  23. }
  24. /**
  25. * The <code>GridBagLayout</code> class is a flexible layout
  26. * manager that aligns components vertically and horizontally,
  27. * without requiring that the components be of the same size.
  28. * Each <code>GridBagLayout</code> object maintains a dynamic
  29. * rectangular grid of cells, with each component occupying
  30. * one or more cells, called its <em>display area</em>.
  31. * <p>
  32. * Each component managed by a grid bag layout is associated
  33. * with an instance of
  34. * {@link GridBagConstraints}
  35. * that specifies how the component is laid out within its display area.
  36. * <p>
  37. * How a <code>GridBagLayout</code> object places a set of components
  38. * depends on the <code>GridBagConstraints</code> object associated
  39. * with each component, and on the minimum size
  40. * and the preferred size of the components' containers.
  41. * <p>
  42. * To use a grid bag layout effectively, you must customize one or more
  43. * of the <code>GridBagConstraints</code> objects that are associated
  44. * with its components. You customize a <code>GridBagConstraints</code>
  45. * object by setting one or more of its instance variables:
  46. * <p>
  47. * <dl>
  48. * <dt>{@link GridBagConstraints#gridx},
  49. * {@link GridBagConstraints#gridy}
  50. * <dd>Specifies the cell at the upper left of the component's display area,
  51. * where the upper-left-most cell has address
  52. * <code>gridx = 0</code>,
  53. * <code>gridy = 0</code>.
  54. * Use <code>GridBagConstraints.RELATIVE</code> (the default value)
  55. * to specify that the component be just placed
  56. * just to the right of (for <code>gridx</code>)
  57. * or just below (for <code>gridy</code>)
  58. * the component that was added to the container
  59. * just before this component was added.
  60. * <dt>{@link GridBagConstraints#gridwidth},
  61. * {@link GridBagConstraints#gridheight}
  62. * <dd>Specifies the number of cells in a row (for <code>gridwidth</code>)
  63. * or column (for <code>gridheight</code>)
  64. * in the component's display area.
  65. * The default value is 1.
  66. * Use <code>GridBagConstraints.REMAINDER</code> to specify
  67. * that the component be the last one in its row (for <code>gridwidth</code>)
  68. * or column (for <code>gridheight</code>).
  69. * Use <code>GridBagConstraints.RELATIVE</code> to specify
  70. * that the component be the next to last one
  71. * in its row (for <code>gridwidth</code>)
  72. * or column (for <code>gridheight</code>).
  73. * <dt>{@link GridBagConstraints#fill}
  74. * <dd>Used when the component's display area
  75. * is larger than the component's requested size
  76. * to determine whether (and how) to resize the component.
  77. * Possible values are
  78. * <code>GridBagConstraints.NONE</code> (the default),
  79. * <code>GridBagConstraints.HORIZONTAL</code>
  80. * (make the component wide enough to fill its display area
  81. * horizontally, but don't change its height),
  82. * <code>GridBagConstraints.VERTICAL</code>
  83. * (make the component tall enough to fill its display area
  84. * vertically, but don't change its width), and
  85. * <code>GridBagConstraints.BOTH</code>
  86. * (make the component fill its display area entirely).
  87. * <dt>{@link GridBagConstraints#ipadx},
  88. * {@link GridBagConstraints#ipady}
  89. * <dd>Specifies the component's internal padding within the layout,
  90. * how much to add to the minimum size of the component.
  91. * The width of the component will be at least its minimum width
  92. * plus <code>(ipadx * 2)</code> pixels (since the padding
  93. * applies to both sides of the component). Similarly, the height of
  94. * the component will be at least the minimum height plus
  95. * <code>(ipady * 2)</code> pixels.
  96. * <dt>{@link GridBagConstraints#insets}
  97. * <dd>Specifies the component's external padding, the minimum
  98. * amount of space between the component and the edges of its display area.
  99. * <dt>{@link GridBagConstraints#anchor}
  100. * <dd>Used when the component is smaller than its display area
  101. * to determine where (within the display area) to place the component.
  102. * Valid values are
  103. * <code>GridBagConstraints.CENTER</code> (the default),
  104. * <code>GridBagConstraints.NORTH</code>,
  105. * <code>GridBagConstraints.NORTHEAST</code>,
  106. * <code>GridBagConstraints.EAST</code>,
  107. * <code>GridBagConstraints.SOUTHEAST</code>,
  108. * <code>GridBagConstraints.SOUTH</code>,
  109. * <code>GridBagConstraints.SOUTHWEST</code>,
  110. * <code>GridBagConstraints.WEST</code>, and
  111. * <code>GridBagConstraints.NORTHWEST</code>.
  112. * <dt>{@link GridBagConstraints#weightx},
  113. * {@link GridBagConstraints#weighty}
  114. * <dd>Used to determine how to distribute space, which is
  115. * important for specifying resizing behavior.
  116. * Unless you specify a weight for at least one component
  117. * in a row (<code>weightx</code>) and column (<code>weighty</code>),
  118. * all the components clump together in the center of their container.
  119. * This is because when the weight is zero (the default),
  120. * the <code>GridBagLayout</code> object puts any extra space
  121. * between its grid of cells and the edges of the container.
  122. * </dl>
  123. * <p>
  124. * The following figure shows ten components (all buttons)
  125. * managed by a grid bag layout:
  126. * <p>
  127. * <img src="doc-files/GridBagLayout-1.gif"
  128. * ALIGN=center HSPACE=10 VSPACE=7>
  129. * <p>
  130. * Each of the ten components has the <code>fill</code> field
  131. * of its associated <code>GridBagConstraints</code> object
  132. * set to <code>GridBagConstraints.BOTH</code>.
  133. * In addition, the components have the following non-default constraints:
  134. * <p>
  135. * <ul>
  136. * <li>Button1, Button2, Button3: <code>weightx = 1.0</code>
  137. * <li>Button4: <code>weightx = 1.0</code>,
  138. * <code>gridwidth = GridBagConstraints.REMAINDER</code>
  139. * <li>Button5: <code>gridwidth = GridBagConstraints.REMAINDER</code>
  140. * <li>Button6: <code>gridwidth = GridBagConstraints.RELATIVE</code>
  141. * <li>Button7: <code>gridwidth = GridBagConstraints.REMAINDER</code>
  142. * <li>Button8: <code>gridheight = 2</code>,
  143. * <code>weighty = 1.0</code>
  144. * <li>Button9, Button 10:
  145. * <code>gridwidth = GridBagConstraints.REMAINDER</code>
  146. * </ul>
  147. * <p>
  148. * Here is the code that implements the example shown above:
  149. * <p>
  150. * <hr><blockquote><pre>
  151. * import java.awt.*;
  152. * import java.util.*;
  153. * import java.applet.Applet;
  154. *
  155. * public class GridBagEx1 extends Applet {
  156. *
  157. * protected void makebutton(String name,
  158. * GridBagLayout gridbag,
  159. * GridBagConstraints c) {
  160. * Button button = new Button(name);
  161. * gridbag.setConstraints(button, c);
  162. * add(button);
  163. * }
  164. *
  165. * public void init() {
  166. * GridBagLayout gridbag = new GridBagLayout();
  167. * GridBagConstraints c = new GridBagConstraints();
  168. *
  169. * setFont(new Font("Helvetica", Font.PLAIN, 14));
  170. * setLayout(gridbag);
  171. *
  172. * c.fill = GridBagConstraints.BOTH;
  173. * c.weightx = 1.0;
  174. * makebutton("Button1", gridbag, c);
  175. * makebutton("Button2", gridbag, c);
  176. * makebutton("Button3", gridbag, c);
  177. *
  178. * c.gridwidth = GridBagConstraints.REMAINDER; //end row
  179. * makebutton("Button4", gridbag, c);
  180. *
  181. * c.weightx = 0.0; //reset to the default
  182. * makebutton("Button5", gridbag, c); //another row
  183. *
  184. * c.gridwidth = GridBagConstraints.RELATIVE; //next-to-last in row
  185. * makebutton("Button6", gridbag, c);
  186. *
  187. * c.gridwidth = GridBagConstraints.REMAINDER; //end row
  188. * makebutton("Button7", gridbag, c);
  189. *
  190. * c.gridwidth = 1; //reset to the default
  191. * c.gridheight = 2;
  192. * c.weighty = 1.0;
  193. * makebutton("Button8", gridbag, c);
  194. *
  195. * c.weighty = 0.0; //reset to the default
  196. * c.gridwidth = GridBagConstraints.REMAINDER; //end row
  197. * c.gridheight = 1; //reset to the default
  198. * makebutton("Button9", gridbag, c);
  199. * makebutton("Button10", gridbag, c);
  200. *
  201. * setSize(300, 100);
  202. * }
  203. *
  204. * public static void main(String args[]) {
  205. * Frame f = new Frame("GridBag Layout Example");
  206. * GridBagEx1 ex1 = new GridBagEx1();
  207. *
  208. * ex1.init();
  209. *
  210. * f.add("Center", ex1);
  211. * f.pack();
  212. * f.setSize(f.getPreferredSize());
  213. * f.show();
  214. * }
  215. * }
  216. * </pre></blockquote><hr>
  217. * <p>
  218. * @version 1.5, 16 Nov 1995
  219. * @author Doug Stein
  220. * @see java.awt.GridBagConstraints
  221. * @since JDK1.0
  222. */
  223. public class GridBagLayout implements LayoutManager2,
  224. java.io.Serializable {
  225. /**
  226. * The maximum number of grid positions (both horizontally and
  227. * vertically) that can be laid out by the grid bag layout.
  228. */
  229. protected static final int MAXGRIDSIZE = 512;
  230. /**
  231. * The smallest grid that can be laid out by the grid bag layout.
  232. */
  233. protected static final int MINSIZE = 1;
  234. protected static final int PREFERREDSIZE = 2;
  235. /**
  236. * This hashtable maintains the association between
  237. * a component and its gridbag constraints.
  238. * The Keys in comptable are the components and the
  239. * values are the instances of GridBagConstraints.
  240. *
  241. * @serial
  242. * @see java.awt.GridBagConstraints
  243. */
  244. protected Hashtable comptable;
  245. /**
  246. * This field holds a gridbag constraints instance
  247. * containing the default values, so if a component
  248. * does not have gridbag constraints associated with
  249. * it, then the component will be assigned a
  250. * copy of the <code>defaultConstraints</code>.
  251. *
  252. * @serial
  253. * @see getConstraints()
  254. * @see setConstraints()
  255. * @see lookupConstraints()
  256. */
  257. protected GridBagConstraints defaultConstraints;
  258. /**
  259. * This field holds tha layout information
  260. * for the gridbag. The information in this field
  261. * is based on the most recent validation of the
  262. * gridbag.
  263. * If <code>layoutInfo</code> is <code>null</code>
  264. * this indicates that there are no components in
  265. * the gridbag or if there are components, they have
  266. * not yet been validated.
  267. *
  268. * @serial
  269. * @see GetLayoutInfo()
  270. */
  271. protected GridBagLayoutInfo layoutInfo;
  272. /**
  273. * This field holds the overrides to the column minimum
  274. * width. If this field is non-null the values are
  275. * applied to the gridbag after all of the minimum columns
  276. * widths have been calculated.
  277. * If columnWidths has more elements than the number of
  278. * columns, columns are added to the gridbag to match
  279. * the number of elements in columnWidth.
  280. *
  281. * @serial
  282. * @see getLayoutDimensions()
  283. */
  284. public int columnWidths[];
  285. /**
  286. * This field holds the overrides to the row minimum
  287. * heights. If this field is non-null the values are
  288. * applied to the gridbag after all of the minimum row
  289. * heights have been calculated.
  290. * If rowHeights has more elements than the number of
  291. * rows, rowa are added to the gridbag to match
  292. * the number of elements in rowHeights.
  293. *
  294. * @serial
  295. * @see getLayoutDimensions()
  296. */
  297. public int rowHeights[];
  298. /**
  299. * This field holds the overrides to the column weights.
  300. * If this field is non-null the values are
  301. * applied to the gridbag after all of the columns
  302. * weights have been calculated.
  303. * If columnWeights[i] > then weight for column i, then
  304. * column i is assigned the weight in columnWeights[i].
  305. * If columnWeights has more elements than the number
  306. * of columns, the excess elements are ignored - they do
  307. * not cause more columns to be created.
  308. *
  309. * @serial
  310. * @see
  311. */
  312. public double columnWeights[];
  313. /**
  314. * This field holds the overrides to the row weights.
  315. * If this field is non-null the values are
  316. * applied to the gridbag after all of the rows
  317. * weights have been calculated.
  318. * If rowWeights[i] > then weight for row i, then
  319. * row i is assigned the weight in rowWeights[i].
  320. * If rowWeights has more elements than the number
  321. * of rows, the excess elements are ignored - they do
  322. * not cause more rows to be created.
  323. *
  324. * @serial
  325. * @see
  326. */
  327. public double rowWeights[];
  328. /**
  329. * Creates a grid bag layout manager.
  330. */
  331. public GridBagLayout () {
  332. comptable = new Hashtable();
  333. defaultConstraints = new GridBagConstraints();
  334. }
  335. /**
  336. * Sets the constraints for the specified component in this layout.
  337. * @param comp the component to be modified.
  338. * @param constraints the constraints to be applied.
  339. */
  340. public void setConstraints(Component comp, GridBagConstraints constraints) {
  341. comptable.put(comp, constraints.clone());
  342. }
  343. /**
  344. * Gets the constraints for the specified component. A copy of
  345. * the actual <code>GridBagConstraints</code> object is returned.
  346. * @param comp the component to be queried.
  347. * @return the constraint for the specified component in this
  348. * grid bag layout; a copy of the actual constraint
  349. * object is returned.
  350. */
  351. public GridBagConstraints getConstraints(Component comp) {
  352. GridBagConstraints constraints = (GridBagConstraints)comptable.get(comp);
  353. if (constraints == null) {
  354. setConstraints(comp, defaultConstraints);
  355. constraints = (GridBagConstraints)comptable.get(comp);
  356. }
  357. return (GridBagConstraints)constraints.clone();
  358. }
  359. /**
  360. * Retrieves the constraints for the specified component.
  361. * The return value is not a copy, but is the actual
  362. * <code>GridBagConstraints</code> object used by the layout mechanism.
  363. * @param comp the component to be queried
  364. * @return the contraints for the specified component.
  365. */
  366. protected GridBagConstraints lookupConstraints(Component comp) {
  367. GridBagConstraints constraints = (GridBagConstraints)comptable.get(comp);
  368. if (constraints == null) {
  369. setConstraints(comp, defaultConstraints);
  370. constraints = (GridBagConstraints)comptable.get(comp);
  371. }
  372. return constraints;
  373. }
  374. /**
  375. * Removes the constraints for the specified component in this layout
  376. * @param comp the component to be modified.
  377. */
  378. private void removeConstraints(Component comp) {
  379. comptable.remove(comp);
  380. }
  381. /**
  382. * Determines the origin of the layout grid.
  383. * Most applications do not call this method directly.
  384. * @return the origin of the cell in the top-left
  385. * corner of the layout grid.
  386. * @since JDK1.1
  387. */
  388. public Point getLayoutOrigin () {
  389. Point origin = new Point(0,0);
  390. if (layoutInfo != null) {
  391. origin.x = layoutInfo.startx;
  392. origin.y = layoutInfo.starty;
  393. }
  394. return origin;
  395. }
  396. /**
  397. * Determines column widths and row heights for the layout grid.
  398. * <p>
  399. * Most applications do not call this method directly.
  400. * @return an array of two arrays, containing the widths
  401. * of the layout columns and
  402. * the heights of the layout rows.
  403. * @since JDK1.1
  404. */
  405. public int [][] getLayoutDimensions () {
  406. if (layoutInfo == null)
  407. return new int[2][0];
  408. int dim[][] = new int [2][];
  409. dim[0] = new int[layoutInfo.width];
  410. dim[1] = new int[layoutInfo.height];
  411. System.arraycopy(layoutInfo.minWidth, 0, dim[0], 0, layoutInfo.width);
  412. System.arraycopy(layoutInfo.minHeight, 0, dim[1], 0, layoutInfo.height);
  413. return dim;
  414. }
  415. /**
  416. * Determines the weights of the layout grid's columns and rows.
  417. * Weights are used to calculate how much a given column or row
  418. * stretches beyond its preferred size, if the layout has extra
  419. * room to fill.
  420. * <p>
  421. * Most applications do not call this method directly.
  422. * @return an array of two arrays, representing the
  423. * horizontal weights of the layout columns
  424. * and the vertical weights of the layout rows.
  425. * @since JDK1.1
  426. */
  427. public double [][] getLayoutWeights () {
  428. if (layoutInfo == null)
  429. return new double[2][0];
  430. double weights[][] = new double [2][];
  431. weights[0] = new double[layoutInfo.width];
  432. weights[1] = new double[layoutInfo.height];
  433. System.arraycopy(layoutInfo.weightX, 0, weights[0], 0, layoutInfo.width);
  434. System.arraycopy(layoutInfo.weightY, 0, weights[1], 0, layoutInfo.height);
  435. return weights;
  436. }
  437. /**
  438. * Determines which cell in the layout grid contains the point
  439. * specified by <code>(x, y)</code>. Each cell is identified
  440. * by its column index (ranging from 0 to the number of columns
  441. * minus 1) and its row index (ranging from 0 to the number of
  442. * rows minus 1).
  443. * <p>
  444. * If the <code>(x, y)</code> point lies
  445. * outside the grid, the following rules are used.
  446. * The column index is returned as zero if <code>x</code> lies to the
  447. * left of the layout, and as the number of columns if <code>x</code> lies
  448. * to the right of the layout. The row index is returned as zero
  449. * if <code>y</code> lies above the layout,
  450. * and as the number of rows if <code>y</code> lies
  451. * below the layout.
  452. * @param x the <i>x</i> coordinate of a point.
  453. * @param y the <i>y</i> coordinate of a point.
  454. * @return an ordered pair of indexes that indicate which cell
  455. * in the layout grid contains the point
  456. * (<i>x</i>, <i>y</i>).
  457. * @since JDK1.1
  458. */
  459. public Point location(int x, int y) {
  460. Point loc = new Point(0,0);
  461. int i, d;
  462. if (layoutInfo == null)
  463. return loc;
  464. d = layoutInfo.startx;
  465. for (i=0; i<layoutInfo.width; i++) {
  466. d += layoutInfo.minWidth[i];
  467. if (d > x)
  468. break;
  469. }
  470. loc.x = i;
  471. d = layoutInfo.starty;
  472. for (i=0; i<layoutInfo.height; i++) {
  473. d += layoutInfo.minHeight[i];
  474. if (d > y)
  475. break;
  476. }
  477. loc.y = i;
  478. return loc;
  479. }
  480. /**
  481. * Adds the specified component with the specified name to the layout.
  482. * @param name the name of the component.
  483. * @param comp the component to be added.
  484. */
  485. public void addLayoutComponent(String name, Component comp) {
  486. }
  487. /**
  488. * Adds the specified component to the layout, using the specified
  489. * constraint object.
  490. * @param comp the component to be added.
  491. * @param constraints an object that determines how
  492. * the component is added to the layout.
  493. */
  494. public void addLayoutComponent(Component comp, Object constraints) {
  495. if (constraints instanceof GridBagConstraints) {
  496. setConstraints(comp, (GridBagConstraints)constraints);
  497. } else if (constraints != null) {
  498. throw new IllegalArgumentException("cannot add to layout: constraint must be a GridBagConstraint");
  499. }
  500. }
  501. /**
  502. * Removes the specified component from this layout.
  503. * <p>
  504. * Most applications do not call this method directly.
  505. * @param comp the component to be removed.
  506. * @see java.awt.Container#remove(java.awt.Component)
  507. * @see java.awt.Container#removeAll()
  508. */
  509. public void removeLayoutComponent(Component comp) {
  510. removeConstraints(comp);
  511. }
  512. /**
  513. * Determines the preferred size of the <code>target</code>
  514. * container using this grid bag layout.
  515. * <p>
  516. * Most applications do not call this method directly.
  517. * @param target the container in which to do the layout.
  518. * @see java.awt.Container#getPreferredSize
  519. */
  520. public Dimension preferredLayoutSize(Container parent) {
  521. GridBagLayoutInfo info = GetLayoutInfo(parent, PREFERREDSIZE);
  522. return GetMinSize(parent, info);
  523. }
  524. /**
  525. * Determines the minimum size of the <code>target</code> container
  526. * using this grid bag layout.
  527. * <p>
  528. * Most applications do not call this method directly.
  529. * @param target the container in which to do the layout.
  530. * @see java.awt.Container#doLayout
  531. */
  532. public Dimension minimumLayoutSize(Container parent) {
  533. GridBagLayoutInfo info = GetLayoutInfo(parent, MINSIZE);
  534. return GetMinSize(parent, info);
  535. }
  536. /**
  537. * Returns the maximum dimensions for this layout given the components
  538. * in the specified target container.
  539. * @param target the component which needs to be laid out
  540. * @see Container
  541. * @see #minimumLayoutSize
  542. * @see #preferredLayoutSize
  543. */
  544. public Dimension maximumLayoutSize(Container target) {
  545. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  546. }
  547. /**
  548. * Returns the alignment along the x axis. This specifies how
  549. * the component would like to be aligned relative to other
  550. * components. The value should be a number between 0 and 1
  551. * where 0 represents alignment along the origin, 1 is aligned
  552. * the furthest away from the origin, 0.5 is centered, etc.
  553. */
  554. public float getLayoutAlignmentX(Container parent) {
  555. return 0.5f;
  556. }
  557. /**
  558. * Returns the alignment along the y axis. This specifies how
  559. * the component would like to be aligned relative to other
  560. * components. The value should be a number between 0 and 1
  561. * where 0 represents alignment along the origin, 1 is aligned
  562. * the furthest away from the origin, 0.5 is centered, etc.
  563. */
  564. public float getLayoutAlignmentY(Container parent) {
  565. return 0.5f;
  566. }
  567. /**
  568. * Invalidates the layout, indicating that if the layout manager
  569. * has cached information it should be discarded.
  570. */
  571. public void invalidateLayout(Container target) {
  572. }
  573. /**
  574. * Lays out the specified container using this grid bag layout.
  575. * This method reshapes components in the specified container in
  576. * order to satisfy the contraints of this <code>GridBagLayout</code>
  577. * object.
  578. * <p>
  579. * Most applications do not call this method directly.
  580. * @param parent the container in which to do the layout.
  581. * @see java.awt.Container
  582. * @see java.awt.Container#doLayout
  583. */
  584. public void layoutContainer(Container parent) {
  585. ArrangeGrid(parent);
  586. }
  587. /**
  588. * Returns a string representation of this grid bag layout's values.
  589. * @return a string representation of this grid bag layout.
  590. */
  591. public String toString() {
  592. return getClass().getName();
  593. }
  594. /**
  595. * Print the layout information. Useful for debugging.
  596. */
  597. /* DEBUG
  598. *
  599. * protected void DumpLayoutInfo(GridBagLayoutInfo s) {
  600. * int x;
  601. *
  602. * System.out.println("Col\tWidth\tWeight");
  603. * for (x=0; x<s.width; x++) {
  604. * System.out.println(x + "\t" +
  605. * s.minWidth[x] + "\t" +
  606. * s.weightX[x]);
  607. * }
  608. * System.out.println("Row\tHeight\tWeight");
  609. * for (x=0; x<s.height; x++) {
  610. * System.out.println(x + "\t" +
  611. * s.minHeight[x] + "\t" +
  612. * s.weightY[x]);
  613. * }
  614. * }
  615. */
  616. /**
  617. * Print the layout constraints. Useful for debugging.
  618. */
  619. /* DEBUG
  620. *
  621. * protected void DumpConstraints(GridBagConstraints constraints) {
  622. * System.out.println(
  623. * "wt " +
  624. * constraints.weightx +
  625. * " " +
  626. * constraints.weighty +
  627. * ", " +
  628. *
  629. * "box " +
  630. * constraints.gridx +
  631. * " " +
  632. * constraints.gridy +
  633. * " " +
  634. * constraints.gridwidth +
  635. * " " +
  636. * constraints.gridheight +
  637. * ", " +
  638. *
  639. * "min " +
  640. * constraints.minWidth +
  641. * " " +
  642. * constraints.minHeight +
  643. * ", " +
  644. *
  645. * "pad " +
  646. * constraints.insets.bottom +
  647. * " " +
  648. * constraints.insets.left +
  649. * " " +
  650. * constraints.insets.right +
  651. * " " +
  652. * constraints.insets.top +
  653. * " " +
  654. * constraints.ipadx +
  655. * " " +
  656. * constraints.ipady);
  657. * }
  658. */
  659. /*
  660. * Fill in an instance of the above structure for the current set
  661. * of managed children. This requires three passes through the
  662. * set of children:
  663. *
  664. * 1) Figure out the dimensions of the layout grid
  665. * 2) Determine which cells the components occupy
  666. * 3) Distribute the weights and min sizes amoung the rows/columns.
  667. *
  668. * This also caches the minsizes for all the children when they are
  669. * first encountered (so subsequent loops don't need to ask again).
  670. */
  671. protected GridBagLayoutInfo GetLayoutInfo(Container parent, int sizeflag) {
  672. synchronized (parent.getTreeLock()) {
  673. GridBagLayoutInfo r = new GridBagLayoutInfo();
  674. Component comp;
  675. GridBagConstraints constraints;
  676. Dimension d;
  677. Component components[] = parent.getComponents();
  678. int compindex, i, j, k, px, py, pixels_diff, nextSize;
  679. int curX, curY, curWidth, curHeight, curRow, curCol;
  680. double weight_diff, weight, start, size;
  681. int xMax[], yMax[];
  682. /*
  683. * Pass #1
  684. *
  685. * Figure out the dimensions of the layout grid (use a value of 1 for
  686. * zero or negative widths and heights).
  687. */
  688. r.width = r.height = 0;
  689. curRow = curCol = -1;
  690. xMax = new int[MAXGRIDSIZE];
  691. yMax = new int[MAXGRIDSIZE];
  692. for (compindex = 0 ; compindex < components.length ; compindex++) {
  693. comp = components[compindex];
  694. if (!comp.isVisible())
  695. continue;
  696. constraints = lookupConstraints(comp);
  697. curX = constraints.gridx;
  698. curY = constraints.gridy;
  699. curWidth = constraints.gridwidth;
  700. if (curWidth <= 0)
  701. curWidth = 1;
  702. curHeight = constraints.gridheight;
  703. if (curHeight <= 0)
  704. curHeight = 1;
  705. /* If x or y is negative, then use relative positioning: */
  706. if (curX < 0 && curY < 0) {
  707. if (curRow >= 0)
  708. curY = curRow;
  709. else if (curCol >= 0)
  710. curX = curCol;
  711. else
  712. curY = 0;
  713. }
  714. if (curX < 0) {
  715. px = 0;
  716. for (i = curY; i < (curY + curHeight); i++)
  717. px = Math.max(px, xMax[i]);
  718. curX = px - curX - 1;
  719. if(curX < 0)
  720. curX = 0;
  721. }
  722. else if (curY < 0) {
  723. py = 0;
  724. for (i = curX; i < (curX + curWidth); i++)
  725. py = Math.max(py, yMax[i]);
  726. curY = py - curY - 1;
  727. if(curY < 0)
  728. curY = 0;
  729. }
  730. /* Adjust the grid width and height */
  731. for (px = curX + curWidth; r.width < px; r.width++);
  732. for (py = curY + curHeight; r.height < py; r.height++);
  733. /* Adjust the xMax and yMax arrays */
  734. for (i = curX; i < (curX + curWidth); i++) { yMax[i] = py; }
  735. for (i = curY; i < (curY + curHeight); i++) { xMax[i] = px; }
  736. /* Cache the current slave's size. */
  737. if (sizeflag == PREFERREDSIZE)
  738. d = comp.getPreferredSize();
  739. else
  740. d = comp.getMinimumSize();
  741. constraints.minWidth = d.width;
  742. constraints.minHeight = d.height;
  743. /* Zero width and height must mean that this is the last item (or
  744. * else something is wrong). */
  745. if (constraints.gridheight == 0 && constraints.gridwidth == 0)
  746. curRow = curCol = -1;
  747. /* Zero width starts a new row */
  748. if (constraints.gridheight == 0 && curRow < 0)
  749. curCol = curX + curWidth;
  750. /* Zero height starts a new column */
  751. else if (constraints.gridwidth == 0 && curCol < 0)
  752. curRow = curY + curHeight;
  753. }
  754. /*
  755. * Apply minimum row/column dimensions
  756. */
  757. if (columnWidths != null && r.width < columnWidths.length)
  758. r.width = columnWidths.length;
  759. if (rowHeights != null && r.height < rowHeights.length)
  760. r.height = rowHeights.length;
  761. /*
  762. * Pass #2
  763. *
  764. * Negative values for gridX are filled in with the current x value.
  765. * Negative values for gridY are filled in with the current y value.
  766. * Negative or zero values for gridWidth and gridHeight end the current
  767. * row or column, respectively.
  768. */
  769. curRow = curCol = -1;
  770. xMax = new int[MAXGRIDSIZE];
  771. yMax = new int[MAXGRIDSIZE];
  772. for (compindex = 0 ; compindex < components.length ; compindex++) {
  773. comp = components[compindex];
  774. if (!comp.isVisible())
  775. continue;
  776. constraints = lookupConstraints(comp);
  777. curX = constraints.gridx;
  778. curY = constraints.gridy;
  779. curWidth = constraints.gridwidth;
  780. curHeight = constraints.gridheight;
  781. /* If x or y is negative, then use relative positioning: */
  782. if (curX < 0 && curY < 0) {
  783. if(curRow >= 0)
  784. curY = curRow;
  785. else if(curCol >= 0)
  786. curX = curCol;
  787. else
  788. curY = 0;
  789. }
  790. if (curX < 0) {
  791. if (curHeight <= 0) {
  792. curHeight += r.height - curY;
  793. if (curHeight < 1)
  794. curHeight = 1;
  795. }
  796. px = 0;
  797. for (i = curY; i < (curY + curHeight); i++)
  798. px = Math.max(px, xMax[i]);
  799. curX = px - curX - 1;
  800. if(curX < 0)
  801. curX = 0;
  802. }
  803. else if (curY < 0) {
  804. if (curWidth <= 0) {
  805. curWidth += r.width - curX;
  806. if (curWidth < 1)
  807. curWidth = 1;
  808. }
  809. py = 0;
  810. for (i = curX; i < (curX + curWidth); i++)
  811. py = Math.max(py, yMax[i]);
  812. curY = py - curY - 1;
  813. if(curY < 0)
  814. curY = 0;
  815. }
  816. if (curWidth <= 0) {
  817. curWidth += r.width - curX;
  818. if (curWidth < 1)
  819. curWidth = 1;
  820. }
  821. if (curHeight <= 0) {
  822. curHeight += r.height - curY;
  823. if (curHeight < 1)
  824. curHeight = 1;
  825. }
  826. px = curX + curWidth;
  827. py = curY + curHeight;
  828. for (i = curX; i < (curX + curWidth); i++) { yMax[i] = py; }
  829. for (i = curY; i < (curY + curHeight); i++) { xMax[i] = px; }
  830. /* Make negative sizes start a new row/column */
  831. if (constraints.gridheight == 0 && constraints.gridwidth == 0)
  832. curRow = curCol = -1;
  833. if (constraints.gridheight == 0 && curRow < 0)
  834. curCol = curX + curWidth;
  835. else if (constraints.gridwidth == 0 && curCol < 0)
  836. curRow = curY + curHeight;
  837. /* Assign the new values to the gridbag slave */
  838. constraints.tempX = curX;
  839. constraints.tempY = curY;
  840. constraints.tempWidth = curWidth;
  841. constraints.tempHeight = curHeight;
  842. }
  843. /*
  844. * Apply minimum row/column dimensions and weights
  845. */
  846. if (columnWidths != null)
  847. System.arraycopy(columnWidths, 0, r.minWidth, 0, columnWidths.length);
  848. if (rowHeights != null)
  849. System.arraycopy(rowHeights, 0, r.minHeight, 0, rowHeights.length);
  850. if (columnWeights != null)
  851. System.arraycopy(columnWeights, 0, r.weightX, 0, columnWeights.length);
  852. if (rowWeights != null)
  853. System.arraycopy(rowWeights, 0, r.weightY, 0, rowWeights.length);
  854. /*
  855. * Pass #3
  856. *
  857. * Distribute the minimun widths and weights:
  858. */
  859. nextSize = Integer.MAX_VALUE;
  860. for (i = 1;
  861. i != Integer.MAX_VALUE;
  862. i = nextSize, nextSize = Integer.MAX_VALUE) {
  863. for (compindex = 0 ; compindex < components.length ; compindex++) {
  864. comp = components[compindex];
  865. if (!comp.isVisible())
  866. continue;
  867. constraints = lookupConstraints(comp);
  868. if (constraints.tempWidth == i) {
  869. px = constraints.tempX + constraints.tempWidth; /* right column */
  870. /*
  871. * Figure out if we should use this slave\'s weight. If the weight
  872. * is less than the total weight spanned by the width of the cell,
  873. * then discard the weight. Otherwise split the difference
  874. * according to the existing weights.
  875. */
  876. weight_diff = constraints.weightx;
  877. for (k = constraints.tempX; k < px; k++)
  878. weight_diff -= r.weightX[k];
  879. if (weight_diff > 0.0) {
  880. weight = 0.0;
  881. for (k = constraints.tempX; k < px; k++)
  882. weight += r.weightX[k];
  883. for (k = constraints.tempX; weight > 0.0 && k < px; k++) {
  884. double wt = r.weightX[k];
  885. double dx = (wt * weight_diff) / weight;
  886. r.weightX[k] += dx;
  887. weight_diff -= dx;
  888. weight -= wt;
  889. }
  890. /* Assign the remainder to the rightmost cell */
  891. r.weightX[px-1] += weight_diff;
  892. }
  893. /*
  894. * Calculate the minWidth array values.
  895. * First, figure out how wide the current slave needs to be.
  896. * Then, see if it will fit within the current minWidth values.
  897. * If it will not fit, add the difference according to the
  898. * weightX array.
  899. */
  900. pixels_diff =
  901. constraints.minWidth + constraints.ipadx +
  902. constraints.insets.left + constraints.insets.right;
  903. for (k = constraints.tempX; k < px; k++)
  904. pixels_diff -= r.minWidth[k];
  905. if (pixels_diff > 0) {
  906. weight = 0.0;
  907. for (k = constraints.tempX; k < px; k++)
  908. weight += r.weightX[k];
  909. for (k = constraints.tempX; weight > 0.0 && k < px; k++) {
  910. double wt = r.weightX[k];
  911. int dx = (int)((wt * ((double)pixels_diff)) / weight);
  912. r.minWidth[k] += dx;
  913. pixels_diff -= dx;
  914. weight -= wt;
  915. }
  916. /* Any leftovers go into the rightmost cell */
  917. r.minWidth[px-1] += pixels_diff;
  918. }
  919. }
  920. else if (constraints.tempWidth > i && constraints.tempWidth < nextSize)
  921. nextSize = constraints.tempWidth;
  922. if (constraints.tempHeight == i) {
  923. py = constraints.tempY + constraints.tempHeight; /* bottom row */
  924. /*
  925. * Figure out if we should use this slave\'s weight. If the weight
  926. * is less than the total weight spanned by the height of the cell,
  927. * then discard the weight. Otherwise split it the difference
  928. * according to the existing weights.
  929. */
  930. weight_diff = constraints.weighty;
  931. for (k = constraints.tempY; k < py; k++)
  932. weight_diff -= r.weightY[k];
  933. if (weight_diff > 0.0) {
  934. weight = 0.0;
  935. for (k = constraints.tempY; k < py; k++)
  936. weight += r.weightY[k];
  937. for (k = constraints.tempY; weight > 0.0 && k < py; k++) {
  938. double wt = r.weightY[k];
  939. double dy = (wt * weight_diff) / weight;
  940. r.weightY[k] += dy;
  941. weight_diff -= dy;
  942. weight -= wt;
  943. }
  944. /* Assign the remainder to the bottom cell */
  945. r.weightY[py-1] += weight_diff;
  946. }
  947. /*
  948. * Calculate the minHeight array values.
  949. * First, figure out how tall the current slave needs to be.
  950. * Then, see if it will fit within the current minHeight values.
  951. * If it will not fit, add the difference according to the
  952. * weightY array.
  953. */
  954. pixels_diff =
  955. constraints.minHeight + constraints.ipady +
  956. constraints.insets.top + constraints.insets.bottom;
  957. for (k = constraints.tempY; k < py; k++)
  958. pixels_diff -= r.minHeight[k];
  959. if (pixels_diff > 0) {
  960. weight = 0.0;
  961. for (k = constraints.tempY; k < py; k++)
  962. weight += r.weightY[k];
  963. for (k = constraints.tempY; weight > 0.0 && k < py; k++) {
  964. double wt = r.weightY[k];
  965. int dy = (int)((wt * ((double)pixels_diff)) / weight);
  966. r.minHeight[k] += dy;
  967. pixels_diff -= dy;
  968. weight -= wt;
  969. }
  970. /* Any leftovers go into the bottom cell */
  971. r.minHeight[py-1] += pixels_diff;
  972. }
  973. }
  974. else if (constraints.tempHeight > i &&
  975. constraints.tempHeight < nextSize)
  976. nextSize = constraints.tempHeight;
  977. }
  978. }
  979. return r;
  980. }
  981. }
  982. /*
  983. * Adjusts the x, y, width, and height fields to the correct
  984. * values depending on the constraint geometry and pads.
  985. */
  986. protected void AdjustForGravity(GridBagConstraints constraints,
  987. Rectangle r) {
  988. int diffx, diffy;
  989. r.x += constraints.insets.left;
  990. r.width -= (constraints.insets.left + constraints.insets.right);
  991. r.y += constraints.insets.top;
  992. r.height -= (constraints.insets.top + constraints.insets.bottom);
  993. diffx = 0;
  994. if ((constraints.fill != GridBagConstraints.HORIZONTAL &&
  995. constraints.fill != GridBagConstraints.BOTH)
  996. && (r.width > (constraints.minWidth + constraints.ipadx))) {
  997. diffx = r.width - (constraints.minWidth + constraints.ipadx);
  998. r.width = constraints.minWidth + constraints.ipadx;
  999. }
  1000. diffy = 0;
  1001. if ((constraints.fill != GridBagConstraints.VERTICAL &&
  1002. constraints.fill != GridBagConstraints.BOTH)
  1003. && (r.height > (constraints.minHeight + constraints.ipady))) {
  1004. diffy = r.height - (constraints.minHeight + constraints.ipady);
  1005. r.height = constraints.minHeight + constraints.ipady;
  1006. }
  1007. switch (constraints.anchor) {
  1008. case GridBagConstraints.CENTER:
  1009. r.x += diffx2;
  1010. r.y += diffy2;
  1011. break;
  1012. case GridBagConstraints.NORTH:
  1013. r.x += diffx2;
  1014. break;
  1015. case GridBagConstraints.NORTHEAST:
  1016. r.x += diffx;
  1017. break;
  1018. case GridBagConstraints.EAST:
  1019. r.x += diffx;
  1020. r.y += diffy2;
  1021. break;
  1022. case GridBagConstraints.SOUTHEAST:
  1023. r.x += diffx;
  1024. r.y += diffy;
  1025. break;
  1026. case GridBagConstraints.SOUTH:
  1027. r.x += diffx2;
  1028. r.y += diffy;
  1029. break;
  1030. case GridBagConstraints.SOUTHWEST:
  1031. r.y += diffy;
  1032. break;
  1033. case GridBagConstraints.WEST:
  1034. r.y += diffy2;
  1035. break;
  1036. case GridBagConstraints.NORTHWEST:
  1037. break;
  1038. default:
  1039. throw new IllegalArgumentException("illegal anchor value");
  1040. }
  1041. }
  1042. /*
  1043. * Figure out the minimum size of the
  1044. * master based on the information from GetLayoutInfo()
  1045. */
  1046. protected Dimension GetMinSize(Container parent, GridBagLayoutInfo info) {
  1047. Dimension d = new Dimension();
  1048. int i, t;
  1049. Insets insets = parent.getInsets();
  1050. t = 0;
  1051. for(i = 0; i < info.width; i++)
  1052. t += info.minWidth[i];
  1053. d.width = t + insets.left + insets.right;
  1054. t = 0;
  1055. for(i = 0; i < info.height; i++)
  1056. t += info.minHeight[i];
  1057. d.height = t + insets.top + insets.bottom;
  1058. return d;
  1059. }
  1060. /*
  1061. * Lay out the grid
  1062. */
  1063. protected void ArrangeGrid(Container parent) {
  1064. Component comp;
  1065. int compindex;
  1066. GridBagConstraints constraints;
  1067. Insets insets = parent.getInsets();
  1068. Component components[] = parent.getComponents();
  1069. Dimension d;
  1070. Rectangle r = new Rectangle();
  1071. int i, diffw, diffh;
  1072. double weight;
  1073. GridBagLayoutInfo info;
  1074. /*
  1075. * If the parent has no slaves anymore, then don't do anything
  1076. * at all: just leave the parent's size as-is.
  1077. */
  1078. if (components.length == 0 &&
  1079. (columnWidths == null || columnWidths.length == 0) &&
  1080. (rowHeights == null || rowHeights.length == 0)) {
  1081. return;
  1082. }
  1083. /*
  1084. * Pass #1: scan all the slaves to figure out the total amount
  1085. * of space needed.
  1086. */
  1087. info = GetLayoutInfo(parent, PREFERREDSIZE);
  1088. d = GetMinSize(parent, info);
  1089. if (parent.width < d.width || parent.height < d.height) {
  1090. info = GetLayoutInfo(parent, MINSIZE);
  1091. d = GetMinSize(parent, info);
  1092. }
  1093. layoutInfo = info;
  1094. r.width = d.width;
  1095. r.height = d.height;
  1096. /*
  1097. * DEBUG
  1098. *
  1099. * DumpLayoutInfo(info);
  1100. * for (compindex = 0 ; compindex < components.length ; compindex++) {
  1101. * comp = components[compindex];
  1102. * if (!comp.isVisible())
  1103. * continue;
  1104. * constraints = lookupConstraints(comp);
  1105. * DumpConstraints(constraints);
  1106. * }
  1107. * System.out.println("minSize " + r.width + " " + r.height);
  1108. */
  1109. /*
  1110. * If the current dimensions of the window don't match the desired
  1111. * dimensions, then adjust the minWidth and minHeight arrays
  1112. * according to the weights.
  1113. */
  1114. diffw = parent.width - r.width;
  1115. if (diffw != 0) {
  1116. weight = 0.0;
  1117. for (i = 0; i < info.width; i++)
  1118. weight += info.weightX[i];
  1119. if (weight > 0.0) {
  1120. for (i = 0; i < info.width; i++) {
  1121. int dx = (int)(( ((double)diffw) * info.weightX[i]) / weight);
  1122. info.minWidth[i] += dx;
  1123. r.width += dx;
  1124. if (info.minWidth[i] < 0) {
  1125. r.width -= info.minWidth[i];
  1126. info.minWidth[i] = 0;
  1127. }
  1128. }
  1129. }
  1130. diffw = parent.width - r.width;
  1131. }
  1132. else {
  1133. diffw = 0;
  1134. }
  1135. diffh = parent.height - r.height;
  1136. if (diffh != 0) {
  1137. weight = 0.0;
  1138. for (i = 0; i < info.height; i++)
  1139. weight += info.weightY[i];
  1140. if (weight > 0.0) {
  1141. for (i = 0; i < info.height; i++) {
  1142. int dy = (int)(( ((double)diffh) * info.weightY[i]) / weight);
  1143. info.minHeight[i] += dy;
  1144. r.height += dy;
  1145. if (info.minHeight[i] < 0) {
  1146. r.height -= info.minHeight[i];
  1147. info.minHeight[i] = 0;
  1148. }
  1149. }
  1150. }
  1151. diffh = parent.height - r.height;
  1152. }
  1153. else {
  1154. diffh = 0;
  1155. }
  1156. /*
  1157. * DEBUG
  1158. *
  1159. * System.out.println("Re-adjusted:");
  1160. * DumpLayoutInfo(info);
  1161. */
  1162. /*
  1163. * Now do the actual layout of the slaves using the layout information
  1164. * that has been collected.
  1165. */
  1166. info.startx = diffw2 + insets.left;
  1167. info.starty = diffh2 + insets.top;
  1168. for (compindex = 0 ; compindex < components.length ; compindex++) {
  1169. comp = components[compindex];
  1170. if (!comp.isVisible())
  1171. continue;
  1172. constraints = lookupConstraints(comp);
  1173. r.x = info.startx;
  1174. for(i = 0; i < constraints.tempX; i++)
  1175. r.x += info.minWidth[i];
  1176. r.y = info.starty;
  1177. for(i = 0; i < constraints.tempY; i++)
  1178. r.y += info.minHeight[i];
  1179. r.width = 0;
  1180. for(i = constraints.tempX;
  1181. i < (constraints.tempX + constraints.tempWidth);
  1182. i++) {
  1183. r.width += info.minWidth[i];
  1184. }
  1185. r.height = 0;
  1186. for(i = constraints.tempY;
  1187. i < (constraints.tempY + constraints.tempHeight);
  1188. i++) {
  1189. r.height += info.minHeight[i];
  1190. }
  1191. AdjustForGravity(constraints, r);
  1192. /*
  1193. * If the window is too small to be interesting then
  1194. * unmap it. Otherwise configure it and then make sure
  1195. * it's mapped.
  1196. */
  1197. if ((r.width <= 0) || (r.height <= 0)) {
  1198. comp.setBounds(0, 0, 0, 0);
  1199. }
  1200. else {
  1201. if (comp.x != r.x || comp.y != r.y ||
  1202. comp.width != r.width || comp.height != r.height) {
  1203. comp.setBounds(r.x, r.y, r.width, r.height);
  1204. }
  1205. }
  1206. }
  1207. }
  1208. }