1. /*
  2. * @(#)CardLayout.java 1.30 00/06/30
  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. import java.util.Enumeration;
  13. /**
  14. * A <code>CardLayout</code> object is a layout manager for a
  15. * container. It treats each component in the container as a card.
  16. * Only one card is visible at a time, and the container acts as
  17. * a stack of cards. The first component added to a
  18. * <code>CardLayout</code> object is the visible component when the
  19. * container is first displayed.
  20. * <p>
  21. * The ordering of cards is determined by the container's own internal
  22. * ordering of its component objects. <code>CardLayout</code>
  23. * defines a set of methods that allow an application to flip
  24. * through these cards sequentially, or to show a specified card.
  25. * The {@link CardLayou#addLayoutComponent}
  26. * method can be used to associate a string identifier with a given card
  27. * for fast random access.
  28. *
  29. * @version 1.30 06/30/00
  30. * @author Arthur van Hoff
  31. * @see java.awt.Container
  32. * @since JDK1.0
  33. */
  34. public class CardLayout implements LayoutManager2,
  35. java.io.Serializable {
  36. /*
  37. * This creates a hashtable, where any non-null object
  38. * can be used as a key or value.
  39. * @serial
  40. * @see java.util.HashTable
  41. */
  42. Hashtable tab = new Hashtable();
  43. /*
  44. * A cards horizontal Layout gap (inset). It specifies
  45. * the space between the left and right edges of a
  46. * container and the current component.
  47. * This should be a non negative Integer.
  48. * @serial
  49. * @see getHgap()
  50. * @see setHgap()
  51. */
  52. int hgap;
  53. /*
  54. * A cards vertical Layout gap (inset). It specifies
  55. * the space between the top and bottom edges of a
  56. * container and the current component.
  57. * This should be a non negative Integer.
  58. * @serial
  59. * @see getVgap()
  60. * @see setVgap()
  61. */
  62. int vgap;
  63. /**
  64. * Creates a new card layout with gaps of size zero.
  65. */
  66. public CardLayout() {
  67. this(0, 0);
  68. }
  69. /**
  70. * Creates a new card layout with the specified horizontal and
  71. * vertical gaps. The horizontal gaps are placed at the left and
  72. * right edges. The vertical gaps are placed at the top and bottom
  73. * edges.
  74. * @param hgap the horizontal gap.
  75. * @param vgap the vertical gap.
  76. */
  77. public CardLayout(int hgap, int vgap) {
  78. this.hgap = hgap;
  79. this.vgap = vgap;
  80. }
  81. /**
  82. * Gets the horizontal gap between components.
  83. * @return the horizontal gap between components.
  84. * @see java.awt.CardLayout#setHgap(int)
  85. * @see java.awt.CardLayout#getVgap()
  86. * @since JDK1.1
  87. */
  88. public int getHgap() {
  89. return hgap;
  90. }
  91. /**
  92. * Sets the horizontal gap between components.
  93. * @param hgap the horizontal gap between components.
  94. * @see java.awt.CardLayout#getHgap()
  95. * @see java.awt.CardLayout#setVgap(int)
  96. * @since JDK1.1
  97. */
  98. public void setHgap(int hgap) {
  99. this.hgap = hgap;
  100. }
  101. /**
  102. * Gets the vertical gap between components.
  103. * @return the vertical gap between components.
  104. * @see java.awt.CardLayout#setVgap(int)
  105. * @see java.awt.CardLayout#getHgap()
  106. */
  107. public int getVgap() {
  108. return vgap;
  109. }
  110. /**
  111. * Sets the vertical gap between components.
  112. * @param vgap the vertical gap between components.
  113. * @see java.awt.CardLayout#getVgap()
  114. * @see java.awt.CardLayout#setHgap(int)
  115. * @since JDK1.1
  116. */
  117. public void setVgap(int vgap) {
  118. this.vgap = vgap;
  119. }
  120. /**
  121. * Adds the specified component to this card layout's internal
  122. * table of names. The object specified by <code>constraints</code>
  123. * must be a string. The card layout stores this string as a key-value
  124. * pair that can be used for random access to a particular card.
  125. * By calling the <code>show</code> method, an application can
  126. * display the component with the specified name.
  127. * @param comp the component to be added.
  128. * @param constraints a tag that identifies a particular
  129. * card in the layout.
  130. * @see java.awt.CardLayout#show(java.awt.Container, java.lang.String)
  131. * @exception IllegalArgumentException if the constraint is not a string.
  132. */
  133. public void addLayoutComponent(Component comp, Object constraints) {
  134. synchronized (comp.getTreeLock()) {
  135. if (constraints instanceof String) {
  136. addLayoutComponent((String)constraints, comp);
  137. } else {
  138. throw new IllegalArgumentException("cannot add to layout: constraint must be a string");
  139. }
  140. }
  141. }
  142. /**
  143. * @deprecated replaced by
  144. * <code>addLayoutComponent(Component, Object)</code>.
  145. */
  146. public void addLayoutComponent(String name, Component comp) {
  147. synchronized (comp.getTreeLock()) {
  148. if (tab.size() > 0) {
  149. comp.hide();
  150. }
  151. tab.put(name, comp);
  152. }
  153. }
  154. /**
  155. * Removes the specified component from the layout.
  156. * If the card was visible on top, the next card underneath it is shown.
  157. * @param comp the component to be removed.
  158. * @see java.awt.Container#remove(java.awt.Component)
  159. * @see java.awt.Container#removeAll()
  160. */
  161. public void removeLayoutComponent(Component comp) {
  162. synchronized (comp.getTreeLock()) {
  163. if (comp.visible) {
  164. next(comp.parent);
  165. }
  166. for (Enumeration e = tab.keys() ; e.hasMoreElements() ; ) {
  167. String key = (String)e.nextElement();
  168. if (tab.get(key) == comp) {
  169. tab.remove(key);
  170. return;
  171. }
  172. }
  173. }
  174. }
  175. /**
  176. * Determines the preferred size of the container argument using
  177. * this card layout.
  178. * @param parent the name of the parent container.
  179. * @return the preferred dimensions to lay out the subcomponents
  180. * of the specified container.
  181. * @see java.awt.Container#getPreferredSize
  182. * @see java.awt.CardLayout#minimumLayoutSize
  183. */
  184. public Dimension preferredLayoutSize(Container parent) {
  185. synchronized (parent.getTreeLock()) {
  186. Insets insets = parent.getInsets();
  187. int ncomponents = parent.getComponentCount();
  188. int w = 0;
  189. int h = 0;
  190. for (int i = 0 ; i < ncomponents ; i++) {
  191. Component comp = parent.getComponent(i);
  192. Dimension d = comp.getPreferredSize();
  193. if (d.width > w) {
  194. w = d.width;
  195. }
  196. if (d.height > h) {
  197. h = d.height;
  198. }
  199. }
  200. return new Dimension(insets.left + insets.right + w + hgap*2,
  201. insets.top + insets.bottom + h + vgap*2);
  202. }
  203. }
  204. /**
  205. * Calculates the minimum size for the specified panel.
  206. * @param parent the name of the parent container
  207. * in which to do the layout.
  208. * @return the minimum dimensions required to lay out the
  209. * subcomponents of the specified container.
  210. * @see java.awt.Container#doLayout
  211. * @see java.awt.CardLayout#preferredLayoutSize
  212. */
  213. public Dimension minimumLayoutSize(Container parent) {
  214. synchronized (parent.getTreeLock()) {
  215. Insets insets = parent.getInsets();
  216. int ncomponents = parent.getComponentCount();
  217. int w = 0;
  218. int h = 0;
  219. for (int i = 0 ; i < ncomponents ; i++) {
  220. Component comp = parent.getComponent(i);
  221. Dimension d = comp.getMinimumSize();
  222. if (d.width > w) {
  223. w = d.width;
  224. }
  225. if (d.height > h) {
  226. h = d.height;
  227. }
  228. }
  229. return new Dimension(insets.left + insets.right + w + hgap*2,
  230. insets.top + insets.bottom + h + vgap*2);
  231. }
  232. }
  233. /**
  234. * Returns the maximum dimensions for this layout given the components
  235. * in the specified target container.
  236. * @param target the component which needs to be laid out
  237. * @see Container
  238. * @see #minimumLayoutSize
  239. * @see #preferredLayoutSize
  240. */
  241. public Dimension maximumLayoutSize(Container target) {
  242. return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
  243. }
  244. /**
  245. * Returns the alignment along the x axis. This specifies how
  246. * the component would like to be aligned relative to other
  247. * components. The value should be a number between 0 and 1
  248. * where 0 represents alignment along the origin, 1 is aligned
  249. * the furthest away from the origin, 0.5 is centered, etc.
  250. */
  251. public float getLayoutAlignmentX(Container parent) {
  252. return 0.5f;
  253. }
  254. /**
  255. * Returns the alignment along the y axis. This specifies how
  256. * the component would like to be aligned relative to other
  257. * components. The value should be a number between 0 and 1
  258. * where 0 represents alignment along the origin, 1 is aligned
  259. * the furthest away from the origin, 0.5 is centered, etc.
  260. */
  261. public float getLayoutAlignmentY(Container parent) {
  262. return 0.5f;
  263. }
  264. /**
  265. * Invalidates the layout, indicating that if the layout manager
  266. * has cached information it should be discarded.
  267. */
  268. public void invalidateLayout(Container target) {
  269. }
  270. /**
  271. * Lays out the specified container using this card layout.
  272. * <p>
  273. * Each component in the <code>parent</code> container is reshaped
  274. * to be the size of the container, minus space for surrounding
  275. * insets, horizontal gaps, and vertical gaps.
  276. *
  277. * @param parent the name of the parent container
  278. * in which to do the layout.
  279. * @see java.awt.Container#doLayout
  280. */
  281. public void layoutContainer(Container parent) {
  282. synchronized (parent.getTreeLock()) {
  283. Insets insets = parent.getInsets();
  284. int ncomponents = parent.getComponentCount();
  285. for (int i = 0 ; i < ncomponents ; i++) {
  286. Component comp = parent.getComponent(i);
  287. if (comp.visible) {
  288. comp.setBounds(hgap + insets.left, vgap + insets.top,
  289. parent.width - (hgap*2 + insets.left + insets.right),
  290. parent.height - (vgap*2 + insets.top + insets.bottom));
  291. }
  292. }
  293. }
  294. }
  295. /**
  296. * Make sure that the Container really has a CardLayout installed.
  297. * Otherwise havoc can ensue!
  298. */
  299. void checkLayout(Container parent) {
  300. if (parent.getLayout() != this) {
  301. throw new IllegalArgumentException("wrong parent for CardLayout");
  302. }
  303. }
  304. /**
  305. * Flips to the first card of the container.
  306. * @param parent the name of the parent container
  307. * in which to do the layout.
  308. * @see java.awt.CardLayout#last
  309. */
  310. public void first(Container parent) {
  311. synchronized (parent.getTreeLock()) {
  312. Component comp;
  313. checkLayout(parent);
  314. int ncomponents = parent.getComponentCount();
  315. for (int i = 1 ; i < ncomponents ; i++) {
  316. comp = parent.getComponent(i);
  317. if (comp.visible) {
  318. comp.hide();
  319. break;
  320. }
  321. }
  322. if (ncomponents > 0) {
  323. comp = parent.getComponent(0);
  324. comp.show();
  325. parent.validate();
  326. }
  327. }
  328. }
  329. /**
  330. * Flips to the next card of the specified container. If the
  331. * currently visible card is the last one, this method flips to the
  332. * first card in the layout.
  333. * @param parent the name of the parent container
  334. * in which to do the layout.
  335. * @see java.awt.CardLayout#previous
  336. */
  337. public void next(Container parent) {
  338. synchronized (parent.getTreeLock()) {
  339. checkLayout(parent);
  340. int ncomponents = parent.getComponentCount();
  341. for (int i = 0 ; i < ncomponents ; i++) {
  342. Component comp = parent.getComponent(i);
  343. if (comp.visible) {
  344. comp.hide();
  345. comp = parent.getComponent((i + 1 < ncomponents) ? i+1 : 0);
  346. comp.show();
  347. parent.validate();
  348. return;
  349. }
  350. }
  351. }
  352. }
  353. /**
  354. * Flips to the previous card of the specified container. If the
  355. * currently visible card is the first one, this method flips to the
  356. * last card in the layout.
  357. * @param parent the name of the parent container
  358. * in which to do the layout.
  359. * @see java.awt.CardLayout#next
  360. */
  361. public void previous(Container parent) {
  362. synchronized (parent.getTreeLock()) {
  363. checkLayout(parent);
  364. int ncomponents = parent.getComponentCount();
  365. for (int i = 0 ; i < ncomponents ; i++) {
  366. Component comp = parent.getComponent(i);
  367. if (comp.visible) {
  368. comp.hide();
  369. comp = parent.getComponent((i > 0) ? i-1 : ncomponents-1);
  370. comp.show();
  371. parent.validate();
  372. return;
  373. }
  374. }
  375. }
  376. }
  377. /**
  378. * Flips to the last card of the container.
  379. * @param parent the name of the parent container
  380. * in which to do the layout.
  381. * @see java.awt.CardLayout#first
  382. */
  383. public void last(Container parent) {
  384. synchronized (parent.getTreeLock()) {
  385. Component comp;
  386. checkLayout(parent);
  387. int ncomponents = parent.getComponentCount();
  388. for (int i = 0 ; i < ncomponents - 1 ; i++) {
  389. comp = parent.getComponent(i);
  390. if (comp.visible) {
  391. comp.hide();
  392. break;
  393. }
  394. }
  395. if (ncomponents > 0) {
  396. comp = parent.getComponent(ncomponents - 1);
  397. comp.show();
  398. parent.validate();
  399. }
  400. }
  401. }
  402. /**
  403. * Flips to the component that was added to this layout with the
  404. * specified <code>name</code>, using <code>addLayoutComponent</code>.
  405. * If no such component exists, then nothing happens.
  406. * @param parent the name of the parent container
  407. * in which to do the layout.
  408. * @param name the component name.
  409. * @see java.awt.CardLayout#addLayoutComponent(java.awt.Component, java.lang.Object)
  410. */
  411. public void show(Container parent, String name) {
  412. synchronized (parent.getTreeLock()) {
  413. checkLayout(parent);
  414. Component next = (Component)tab.get(name);
  415. if ((next != null) && !next.visible){
  416. int ncomponents = parent.getComponentCount();
  417. for (int i = 0 ; i < ncomponents ; i++) {
  418. Component comp = parent.getComponent(i);
  419. if (comp.visible) {
  420. comp.hide();
  421. break;
  422. }
  423. }
  424. next.show();
  425. parent.validate();
  426. }
  427. }
  428. }
  429. /**
  430. * Returns a string representation of the state of this card layout.
  431. * @return a string representation of this card layout.
  432. */
  433. public String toString() {
  434. return getClass().getName() + "[hgap=" + hgap + ",vgap=" + vgap + "]";
  435. }
  436. }