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