1. /*
  2. * @(#)JApplet.java 1.56 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import java.awt.*;
  9. import java.awt.event.*;
  10. import java.applet.Applet;
  11. import java.beans.PropertyChangeListener;
  12. import java.util.Locale;
  13. import java.util.Vector;
  14. import java.io.Serializable;
  15. import javax.accessibility.*;
  16. /**
  17. * An extended version of java.applet.Applet that adds support for
  18. * the JFC/Swing component architecture.
  19. * You can find task-oriented documentation about using <code>JApplet</code>
  20. * in <em>The Java Tutorial</em>,
  21. * in the section
  22. * <a
  23. href="http://java.sun.com/docs/books/tutorial/uiswing/components/applet.html">How to Make Applets</a>.
  24. * <p>
  25. * The JApplet class is slightly incompatible with java.applet.Applet.
  26. * JApplet contains a JRootPane as it's only child.
  27. * The <b>contentPane</b> should be the parent of any children of the JApplet.
  28. * This is different than java.applet.Applet, e.g. to add a child to
  29. * an an java.applet.Applet you'd write:
  30. * <pre>
  31. * applet.add(child);
  32. * </pre>
  33. * However using JApplet you need to add the child to the JApplet's contentPane
  34. * instead:
  35. * <pre>
  36. * applet.getContentPane().add(child);
  37. * </pre>
  38. * The same is true for setting LayoutManagers, removing components,
  39. * listing children, etc. All these methods should normally be sent to
  40. * the contentPane() instead of the JApplet itself. The contentPane() will
  41. * always be non-null. Attempting to set it to null will cause the JApplet
  42. * to throw an exception. The default contentPane() will have a BorderLayout
  43. * manager set on it.
  44. * <p>
  45. * Please see the JRootPane documentation for a complete description of
  46. * the contentPane, glassPane, and layeredPane properties.
  47. * <p>
  48. * For the keyboard keys used by this component in the standard Look and
  49. * Feel (L&F) renditions, see the
  50. * <a href="doc-files/Key-Index.html#JApplet"><code>JApplet</code> key assignments</a>.
  51. * <p>
  52. * <strong>Warning:</strong>
  53. * Serialized objects of this class will not be compatible with
  54. * future Swing releases. The current serialization support is
  55. * appropriate for short term storage or RMI between applications running
  56. * the same version of Swing. As of 1.4, support for long term storage
  57. * of all JavaBeans<sup><font size="-2">TM</font></sup>
  58. * has been added to the <code>java.beans</code> package.
  59. * Please see {@link java.beans.XMLEncoder}.
  60. *
  61. * @beaninfo
  62. * attribute: isContainer true
  63. * attribute: containerDelegate getContentPane
  64. * description: Swing's Applet subclass.
  65. *
  66. * @version 1.56 01/23/03
  67. * @author Arnaud Weber
  68. */
  69. public class JApplet extends Applet implements Accessible, RootPaneContainer
  70. {
  71. /**
  72. * @see #getRootPane
  73. * @see #setRootPane
  74. */
  75. protected JRootPane rootPane;
  76. /**
  77. * @see #isRootPaneCheckingEnabled
  78. * @see #setRootPaneCheckingEnabled
  79. */
  80. protected boolean rootPaneCheckingEnabled = false;
  81. /**
  82. * Creates a swing applet instance.
  83. * <p>
  84. * This constructor sets the component's locale property to the value
  85. * returned by <code>JComponent.getDefaultLocale</code>.
  86. *
  87. * @exception HeadlessException if GraphicsEnvironment.isHeadless()
  88. * returns true.
  89. * @see java.awt.GraphicsEnvironment#isHeadless
  90. * @see JComponent#getDefaultLocale
  91. */
  92. public JApplet() throws HeadlessException {
  93. super();
  94. // Check the timerQ and restart if necessary.
  95. TimerQueue q = TimerQueue.sharedInstance();
  96. if(q != null) {
  97. synchronized(q) {
  98. if(!q.running)
  99. q.start();
  100. }
  101. }
  102. /* Workaround for bug 4155072. The shared double buffer image
  103. * may hang on to a reference to this applet; unfortunately
  104. * Image.getGraphics() will continue to call JApplet.getForeground()
  105. * and getBackground() even after this applet has been destroyed.
  106. * So we ensure that these properties are non-null here.
  107. */
  108. setForeground(Color.black);
  109. setBackground(Color.white);
  110. setLocale( JComponent.getDefaultLocale() );
  111. setLayout(new BorderLayout());
  112. setRootPane(createRootPane());
  113. setRootPaneCheckingEnabled(true);
  114. // This code should be changed after the RFE 4719336 is resolved
  115. // to not make the applet a FocusCycleRoot, but set it's
  116. // FocusTraversalPolicy only.
  117. setFocusCycleRoot(true);
  118. setFocusTraversalPolicy(KeyboardFocusManager.
  119. getCurrentKeyboardFocusManager().
  120. getDefaultFocusTraversalPolicy());
  121. enableEvents(AWTEvent.KEY_EVENT_MASK);
  122. }
  123. /** Called by the constructor methods to create the default rootPane. */
  124. protected JRootPane createRootPane() {
  125. return new JRootPane();
  126. }
  127. /**
  128. * Just calls <code>paint(g)</code>. This method was overridden to
  129. * prevent an unnecessary call to clear the background.
  130. */
  131. public void update(Graphics g) {
  132. paint(g);
  133. }
  134. /**
  135. * Sets the menubar for this applet.
  136. * @param menuBar the menubar being placed in the applet
  137. *
  138. * @see #getJMenuBar
  139. *
  140. * @beaninfo
  141. * hidden: true
  142. * description: The menubar for accessing pulldown menus from this applet.
  143. */
  144. public void setJMenuBar(JMenuBar menuBar) {
  145. getRootPane().setMenuBar(menuBar);
  146. }
  147. /**
  148. * Returns the menubar set on this applet.
  149. *
  150. * @see #setJMenuBar
  151. */
  152. public JMenuBar getJMenuBar() {
  153. return getRootPane().getMenuBar();
  154. }
  155. /**
  156. * @return true if add and setLayout should be checked
  157. * @see #addImpl
  158. * @see #setLayout
  159. * @see #setRootPaneCheckingEnabled
  160. */
  161. protected boolean isRootPaneCheckingEnabled() {
  162. return rootPaneCheckingEnabled;
  163. }
  164. /**
  165. * If true then calls to add() and setLayout() will cause an exception
  166. * to be thrown.
  167. *
  168. * @see #addImpl
  169. * @see #setLayout
  170. * @see #isRootPaneCheckingEnabled
  171. */
  172. protected void setRootPaneCheckingEnabled(boolean enabled) {
  173. rootPaneCheckingEnabled = enabled;
  174. }
  175. /**
  176. * Create an runtime exception with a message like:
  177. * <pre>
  178. * "Do not use JApplet.add() use JApplet.getContentPane().add() instead"
  179. * </pre>
  180. */
  181. private Error createRootPaneException(String op) {
  182. String type = getClass().getName();
  183. return new Error(
  184. "Do not use " + type + "." + op + "() use "
  185. + type + ".getContentPane()." + op + "() instead");
  186. }
  187. /**
  188. * By default, children may not be added directly to a this component,
  189. * they must be added to its contentPane instead. For example:
  190. * <pre>
  191. * thiComponent.getContentPane().add(child)
  192. * </pre>
  193. * An attempt to add to directly to this component will cause an
  194. * runtime exception to be thrown. Subclasses can disable this
  195. * behavior.
  196. *
  197. * @see #setRootPaneCheckingEnabled
  198. * @exception Error if called with rootPaneChecking true
  199. */
  200. protected void addImpl(Component comp, Object constraints, int index)
  201. {
  202. if(isRootPaneCheckingEnabled()) {
  203. throw createRootPaneException("add");
  204. }
  205. else {
  206. super.addImpl(comp, constraints, index);
  207. }
  208. }
  209. /**
  210. * Removes the specified component from this container.
  211. * @param comp the component to be removed
  212. * @see #add
  213. */
  214. public void remove(Component comp) {
  215. if (comp == rootPane) {
  216. super.remove(comp);
  217. } else {
  218. // Client mistake, but we need to handle it to avoid a
  219. // common object leak in client applications.
  220. getContentPane().remove(comp);
  221. }
  222. }
  223. /**
  224. * By default the layout of this component may not be set,
  225. * the layout of its contentPane should be set instead.
  226. * For example:
  227. * <pre>
  228. * thisComponent.getContentPane().setLayout(new GridLayout(1, 2))
  229. * </pre>
  230. * An attempt to set the layout of this component will cause an
  231. * runtime exception to be thrown. Subclasses can disable this
  232. * behavior.
  233. *
  234. * @see #setRootPaneCheckingEnabled
  235. * @exception Error if called with rootPaneChecking true
  236. */
  237. public void setLayout(LayoutManager manager) {
  238. if(isRootPaneCheckingEnabled()) {
  239. throw createRootPaneException("setLayout");
  240. }
  241. else {
  242. super.setLayout(manager);
  243. }
  244. }
  245. /**
  246. * Returns the rootPane object for this applet.
  247. *
  248. * @see #setRootPane
  249. * @see RootPaneContainer#getRootPane
  250. */
  251. public JRootPane getRootPane() {
  252. return rootPane;
  253. }
  254. /**
  255. * Sets the rootPane property. This method is called by the constructor.
  256. * @param root the rootPane object for this applet
  257. *
  258. * @see #getRootPane
  259. *
  260. * @beaninfo
  261. * hidden: true
  262. * description: the RootPane object for this applet.
  263. */
  264. protected void setRootPane(JRootPane root) {
  265. if(rootPane != null) {
  266. remove(rootPane);
  267. }
  268. rootPane = root;
  269. if(rootPane != null) {
  270. boolean checkingEnabled = isRootPaneCheckingEnabled();
  271. try {
  272. setRootPaneCheckingEnabled(false);
  273. add(rootPane, BorderLayout.CENTER);
  274. }
  275. finally {
  276. setRootPaneCheckingEnabled(checkingEnabled);
  277. }
  278. }
  279. }
  280. /**
  281. * Returns the contentPane object for this applet.
  282. *
  283. * @see #setContentPane
  284. * @see RootPaneContainer#getContentPane
  285. */
  286. public Container getContentPane() {
  287. return getRootPane().getContentPane();
  288. }
  289. /**
  290. * Sets the contentPane property. This method is called by the constructor.
  291. * @param contentPane the contentPane object for this applet
  292. *
  293. * @exception java.awt.IllegalComponentStateException (a runtime
  294. * exception) if the content pane parameter is null
  295. * @see #getContentPane
  296. * @see RootPaneContainer#setContentPane
  297. *
  298. * @beaninfo
  299. * hidden: true
  300. * description: The client area of the applet where child
  301. * components are normally inserted.
  302. */
  303. public void setContentPane(Container contentPane) {
  304. getRootPane().setContentPane(contentPane);
  305. }
  306. /**
  307. * Returns the layeredPane object for this applet.
  308. *
  309. * @exception java.awt.IllegalComponentStateException (a runtime
  310. * exception) if the layered pane parameter is null
  311. * @see #setLayeredPane
  312. * @see RootPaneContainer#getLayeredPane
  313. */
  314. public JLayeredPane getLayeredPane() {
  315. return getRootPane().getLayeredPane();
  316. }
  317. /**
  318. * Sets the layeredPane property. This method is called by the constructor.
  319. * @param layeredPane the layeredPane object for this applet
  320. *
  321. * @see #getLayeredPane
  322. * @see RootPaneContainer#setLayeredPane
  323. *
  324. * @beaninfo
  325. * hidden: true
  326. * description: The pane which holds the various applet layers.
  327. */
  328. public void setLayeredPane(JLayeredPane layeredPane) {
  329. getRootPane().setLayeredPane(layeredPane);
  330. }
  331. /**
  332. * Returns the glassPane object for this applet.
  333. *
  334. * @see #setGlassPane
  335. * @see RootPaneContainer#getGlassPane
  336. */
  337. public Component getGlassPane() {
  338. return getRootPane().getGlassPane();
  339. }
  340. /**
  341. * Sets the glassPane property.
  342. * This method is called by the constructor.
  343. * @param glassPane the glassPane object for this applet
  344. *
  345. * @see #getGlassPane
  346. * @see RootPaneContainer#setGlassPane
  347. *
  348. * @beaninfo
  349. * hidden: true
  350. * description: A transparent pane used for menu rendering.
  351. */
  352. public void setGlassPane(Component glassPane) {
  353. getRootPane().setGlassPane(glassPane);
  354. }
  355. /**
  356. * Returns a string representation of this JApplet. This method
  357. * is intended to be used only for debugging purposes, and the
  358. * content and format of the returned string may vary between
  359. * implementations. The returned string may be empty but may not
  360. * be <code>null</code>.
  361. *
  362. * @return a string representation of this JApplet.
  363. */
  364. protected String paramString() {
  365. String rootPaneString = (rootPane != null ?
  366. rootPane.toString() : "");
  367. String rootPaneCheckingEnabledString = (rootPaneCheckingEnabled ?
  368. "true" : "false");
  369. return super.paramString() +
  370. ",rootPane=" + rootPaneString +
  371. ",rootPaneCheckingEnabled=" + rootPaneCheckingEnabledString;
  372. }
  373. /////////////////
  374. // Accessibility support
  375. ////////////////
  376. protected AccessibleContext accessibleContext = null;
  377. /**
  378. * Gets the AccessibleContext associated with this JApplet.
  379. * For JApplets, the AccessibleContext takes the form of an
  380. * AccessibleJApplet.
  381. * A new AccessibleJApplet instance is created if necessary.
  382. *
  383. * @return an AccessibleJApplet that serves as the
  384. * AccessibleContext of this JApplet
  385. */
  386. public AccessibleContext getAccessibleContext() {
  387. if (accessibleContext == null) {
  388. accessibleContext = new AccessibleJApplet();
  389. }
  390. return accessibleContext;
  391. }
  392. /**
  393. * This class implements accessibility support for the
  394. * <code>JApplet</code> class.
  395. */
  396. protected class AccessibleJApplet extends AccessibleApplet {
  397. // everything moved to new parent, AccessibleApplet
  398. }
  399. }