1. /*
  2. * @(#)Container.java 1.163 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.io.PrintStream;
  9. import java.io.PrintWriter;
  10. import java.awt.peer.ContainerPeer;
  11. import java.awt.peer.ComponentPeer;
  12. import java.awt.event.KeyEvent;
  13. import java.awt.event.MouseEvent;
  14. import java.awt.event.FocusEvent;
  15. import java.awt.event.ContainerEvent;
  16. import java.awt.event.ContainerListener;
  17. import java.io.ObjectOutputStream;
  18. import java.io.ObjectInputStream;
  19. import java.io.IOException;
  20. import java.awt.event.AWTEventListener;
  21. import java.awt.event.WindowAdapter;
  22. import java.awt.event.WindowListener;
  23. import java.awt.event.WindowEvent;
  24. /**
  25. * A generic Abstract Window Toolkit(AWT) container object is a component
  26. * that can contain other AWT components.
  27. * <p>
  28. * Components added to a container are tracked in a list. The order
  29. * of the list will define the components' front-to-back stacking order
  30. * within the container. If no index is specified when adding a
  31. * component to a container, it will be added to the end of the list
  32. * (and hence to the bottom of the stacking order).
  33. * @version 1.163 11/29/01
  34. * @author Arthur van Hoff
  35. * @author Sami Shaio
  36. * @see java.awt.Container#add(java.awt.Component, int)
  37. * @see java.awt.Container#getComponent(int)
  38. * @see java.awt.LayoutManager
  39. * @since JDK1.0
  40. */
  41. public class Container extends Component {
  42. /**
  43. * The number of components in this container.
  44. * This value can be null.
  45. * @serial
  46. * @see getComponent()
  47. * @see getComponents()
  48. * @see getComponentCount()
  49. */
  50. int ncomponents;
  51. /**
  52. * The components in this container.
  53. * @serial
  54. * @see add()
  55. * @see getComponents()
  56. */
  57. Component component[] = new Component[4];
  58. /**
  59. * Layout manager for this container.
  60. * @serial
  61. * @see doLayout()
  62. * @see setLayout()
  63. * @see getLayout()
  64. */
  65. LayoutManager layoutMgr;
  66. /**
  67. * Event router for lightweight components. If this container
  68. * is native, this dispatcher takes care of forwarding and
  69. * retargeting the events to lightweight components contained
  70. * (if any).
  71. * @serial
  72. */
  73. private LightweightDispatcher dispatcher;
  74. /*
  75. * Internal, cached size information.
  76. * @serial
  77. * @see getMaximumSize()
  78. * @see getPreferredSize()
  79. */
  80. private Dimension maxSize;
  81. transient ContainerListener containerListener;
  82. /*
  83. * JDK 1.1 serialVersionUID
  84. */
  85. private static final long serialVersionUID = 4613797578919906343L;
  86. static {
  87. /* ensure that the necessary native libraries are loaded */
  88. Toolkit.loadLibraries();
  89. initIDs();
  90. }
  91. /**
  92. * Initialize JNI field and method IDs for fields that may be
  93. called from C.
  94. */
  95. private static native void initIDs();
  96. /**
  97. * Constructs a new Container. Containers can be extended directly,
  98. * but are lightweight in this case and must be contained by a parent
  99. * somewhere higher up in the component tree that is native.
  100. * (such as Frame for example).
  101. */
  102. public Container() {
  103. }
  104. /**
  105. * Gets the number of components in this panel.
  106. * @return the number of components in this panel.
  107. * @see java.awt.Container#getComponent
  108. * @since JDK1.1
  109. */
  110. public int getComponentCount() {
  111. return countComponents();
  112. }
  113. /**
  114. * @deprecated As of JDK version 1.1,
  115. * replaced by getComponentCount().
  116. */
  117. public int countComponents() {
  118. return ncomponents;
  119. }
  120. /**
  121. * Gets the nth component in this container.
  122. * @param n the index of the component to get.
  123. * @return the n<sup>th</sup> component in this container.
  124. * @exception ArrayIndexOutOfBoundsException
  125. * if the n<sup>th</sup> value does not exist.
  126. */
  127. public Component getComponent(int n) {
  128. synchronized (getTreeLock()) {
  129. if ((n < 0) || (n >= ncomponents)) {
  130. throw new ArrayIndexOutOfBoundsException("No such child: " + n);
  131. }
  132. return component[n];
  133. }
  134. }
  135. /**
  136. * Gets all the components in this container.
  137. * @return an array of all the components in this container.
  138. */
  139. public Component[] getComponents() {
  140. return getComponents_NoClientCode();
  141. }
  142. // NOTE: This method may be called by privileged threads.
  143. // This functionality is implemented in a package-private method
  144. // to insure that it cannot be overridden by client subclasses.
  145. // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
  146. final Component[] getComponents_NoClientCode() {
  147. synchronized (getTreeLock()) {
  148. Component list[] = new Component[ncomponents];
  149. System.arraycopy(component, 0, list, 0, ncomponents);
  150. return list;
  151. }
  152. } // getComponents_NoClientCode()
  153. /**
  154. * Determines the insets of this container, which indicate the size
  155. * of the container's border.
  156. * <p>
  157. * A <code>Frame</code> object, for example, has a top inset that
  158. * corresponds to the height of the frame's title bar.
  159. * @return the insets of this container.
  160. * @see java.awt.Insets
  161. * @see java.awt.LayoutManager
  162. * @since JDK1.1
  163. */
  164. public Insets getInsets() {
  165. return insets();
  166. }
  167. /**
  168. * @deprecated As of JDK version 1.1,
  169. * replaced by <code>getInsets()</code>.
  170. */
  171. public Insets insets() {
  172. if (this.peer != null && this.peer instanceof ContainerPeer) {
  173. ContainerPeer peer = (ContainerPeer)this.peer;
  174. return (Insets)peer.insets().clone();
  175. }
  176. return new Insets(0, 0, 0, 0);
  177. }
  178. /**
  179. * Adds the specified component to the end of this container.
  180. * @param comp the component to be added.
  181. * @return the component argument.
  182. */
  183. public Component add(Component comp) {
  184. addImpl(comp, null, -1);
  185. return comp;
  186. }
  187. /**
  188. * Adds the specified component to this container.
  189. * It is strongly advised to use the 1.1 method, add(Component, Object),
  190. * in place of this method.
  191. */
  192. public Component add(String name, Component comp) {
  193. addImpl(comp, name, -1);
  194. return comp;
  195. }
  196. /**
  197. * Adds the specified component to this container at the given
  198. * position.
  199. * @param comp the component to be added.
  200. * @param index the position at which to insert the component,
  201. * or <code>-1</code> to insert the component at the end.
  202. * @return the component <code>comp</code>
  203. * @see #remove
  204. */
  205. public Component add(Component comp, int index) {
  206. addImpl(comp, null, index);
  207. return comp;
  208. }
  209. /**
  210. * Adds the specified component to the end of this container.
  211. * Also notifies the layout manager to add the component to
  212. * this container's layout using the specified constraints object.
  213. * @param comp the component to be added
  214. * @param constraints an object expressing
  215. * layout contraints for this component
  216. * @see java.awt.LayoutManager
  217. * @since JDK1.1
  218. */
  219. public void add(Component comp, Object constraints) {
  220. addImpl(comp, constraints, -1);
  221. }
  222. /**
  223. * Adds the specified component to this container with the specified
  224. * constraints at the specified index. Also notifies the layout
  225. * manager to add the component to the this container's layout using
  226. * the specified constraints object.
  227. * @param comp the component to be added
  228. * @param constraints an object expressing layout contraints for this
  229. * @param index the position in the container's list at which to insert
  230. * the component. -1 means insert at the end.
  231. * component
  232. * @see #remove
  233. * @see LayoutManager
  234. */
  235. public void add(Component comp, Object constraints, int index) {
  236. addImpl(comp, constraints, index);
  237. }
  238. /**
  239. * Adds the specified component to this container at the specified
  240. * index. This method also notifies the layout manager to add
  241. * the component to this container's layout using the specified
  242. * constraints object.
  243. * <p>
  244. * This is the method to override if a program needs to track
  245. * every add request to a container. An overriding method should
  246. * usually include a call to the superclass's version of the method:
  247. * <p>
  248. * <blockquote>
  249. * <code>super.addImpl(comp, constraints, index)</code>
  250. * </blockquote>
  251. * <p>
  252. * @param comp the component to be added.
  253. * @param constraints an object expressing layout contraints
  254. * for this component.
  255. * @param index the position in the container's list at which to
  256. * insert the component, where <code>-1</code>
  257. * means insert at the end.
  258. * @see java.awt.Container#add(java.awt.Component)
  259. * @see java.awt.Container#add(java.awt.Component, int)
  260. * @see java.awt.Container#add(java.awt.Component, java.lang.Object)
  261. * @see java.awt.LayoutManager
  262. * @since JDK1.1
  263. */
  264. protected void addImpl(Component comp, Object constraints, int index) {
  265. synchronized (getTreeLock()) {
  266. /* Check for correct arguments: index in bounds,
  267. * comp cannot be one of this container's parents,
  268. * and comp cannot be a window.
  269. */
  270. if (index > ncomponents || (index < 0 && index != -1)) {
  271. throw new IllegalArgumentException(
  272. "illegal component position");
  273. }
  274. if (comp instanceof Container) {
  275. for (Container cn = this; cn != null; cn=cn.parent) {
  276. if (cn == comp) {
  277. throw new IllegalArgumentException(
  278. "adding container's parent to itself");
  279. }
  280. }
  281. }
  282. if (comp instanceof Window) {
  283. throw new IllegalArgumentException(
  284. "adding a window to a container");
  285. }
  286. /* Reparent the component and tidy up the tree's state. */
  287. if (comp.parent != null) {
  288. comp.parent.remove(comp);
  289. }
  290. /* Add component to list; allocate new array if necessary. */
  291. if (ncomponents == component.length) {
  292. Component newcomponents[] = new Component[ncomponents * 2];
  293. System.arraycopy(component, 0, newcomponents, 0, ncomponents);
  294. component = newcomponents;
  295. }
  296. if (index == -1 || index == ncomponents) {
  297. component[ncomponents++] = comp;
  298. } else {
  299. System.arraycopy(component, index, component,
  300. index + 1, ncomponents - index);
  301. component[index] = comp;
  302. ncomponents++;
  303. }
  304. comp.parent = this;
  305. if (valid) {
  306. invalidate();
  307. }
  308. if (peer != null) {
  309. comp.addNotify();
  310. }
  311. /* Notify the layout manager of the added component. */
  312. if (layoutMgr != null) {
  313. if (layoutMgr instanceof LayoutManager2) {
  314. ((LayoutManager2)layoutMgr).addLayoutComponent(comp, constraints);
  315. } else if (constraints instanceof String) {
  316. layoutMgr.addLayoutComponent((String)constraints, comp);
  317. }
  318. }
  319. if (containerListener != null ||
  320. (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) {
  321. ContainerEvent e = new ContainerEvent(this,
  322. ContainerEvent.COMPONENT_ADDED,
  323. comp);
  324. processEvent(e);
  325. }
  326. }
  327. }
  328. /**
  329. * Removes the component, specified by <code>index</code>,
  330. * from this container.
  331. * @param index the index of the component to be removed.
  332. * @see #add
  333. * @since JDK1.1
  334. */
  335. public void remove(int index) {
  336. synchronized (getTreeLock()) {
  337. Component comp = component[index];
  338. if (peer != null) {
  339. comp.removeNotify();
  340. }
  341. if (layoutMgr != null) {
  342. layoutMgr.removeLayoutComponent(comp);
  343. }
  344. comp.parent = null;
  345. System.arraycopy(component, index + 1,
  346. component, index,
  347. ncomponents - index - 1);
  348. component[--ncomponents] = null;
  349. if (valid) {
  350. invalidate();
  351. }
  352. if (containerListener != null ||
  353. (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) {
  354. ContainerEvent e = new ContainerEvent(this,
  355. ContainerEvent.COMPONENT_REMOVED,
  356. comp);
  357. processEvent(e);
  358. }
  359. return;
  360. }
  361. }
  362. /**
  363. * Removes the specified component from this container.
  364. * @param comp the component to be removed
  365. * @see #add
  366. */
  367. public void remove(Component comp) {
  368. synchronized (getTreeLock()) {
  369. if (comp.parent == this) {
  370. /* Search backwards, expect that more recent additions
  371. * are more likely to be removed.
  372. */
  373. Component component[] = this.component;
  374. for (int i = ncomponents; --i >= 0; ) {
  375. if (component[i] == comp) {
  376. remove(i);
  377. }
  378. }
  379. }
  380. }
  381. }
  382. /**
  383. * Removes all the components from this container.
  384. * @see #add
  385. * @see #remove
  386. */
  387. public void removeAll() {
  388. synchronized (getTreeLock()) {
  389. while (ncomponents > 0) {
  390. Component comp = component[--ncomponents];
  391. component[ncomponents] = null;
  392. if (peer != null) {
  393. comp.removeNotify();
  394. }
  395. if (layoutMgr != null) {
  396. layoutMgr.removeLayoutComponent(comp);
  397. }
  398. comp.parent = null;
  399. if (containerListener != null ||
  400. (eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0) {
  401. ContainerEvent e = new ContainerEvent(this,
  402. ContainerEvent.COMPONENT_REMOVED,
  403. comp);
  404. processEvent(e);
  405. }
  406. }
  407. if (valid) {
  408. invalidate();
  409. }
  410. }
  411. }
  412. /**
  413. * Gets the layout manager for this container.
  414. * @see #doLayout
  415. * @see #setLayout
  416. */
  417. public LayoutManager getLayout() {
  418. return layoutMgr;
  419. }
  420. /**
  421. * Sets the layout manager for this container.
  422. * @param mgr the specified layout manager
  423. * @see #doLayout
  424. * @see #getLayout
  425. */
  426. public void setLayout(LayoutManager mgr) {
  427. layoutMgr = mgr;
  428. if (valid) {
  429. invalidate();
  430. }
  431. }
  432. /**
  433. * Causes this container to lay out its components. Most programs
  434. * should not call this method directly, but should invoke
  435. * the <code>validate</code> method instead.
  436. * @see java.awt.LayoutManager#layoutContainer
  437. * @see #setLayout
  438. * @see #validate
  439. * @since JDK1.1
  440. */
  441. public void doLayout() {
  442. layout();
  443. }
  444. /**
  445. * @deprecated As of JDK version 1.1,
  446. * replaced by <code>doLayout()</code>.
  447. */
  448. public void layout() {
  449. LayoutManager layoutMgr = this.layoutMgr;
  450. if (layoutMgr != null) {
  451. layoutMgr.layoutContainer(this);
  452. }
  453. }
  454. /**
  455. * Invalidates the container. The container and all parents
  456. * above it are marked as needing to be laid out. This method can
  457. * be called often, so it needs to execute quickly.
  458. * @see #validate
  459. * @see #layout
  460. * @see LayoutManager
  461. */
  462. public void invalidate() {
  463. if (layoutMgr instanceof LayoutManager2) {
  464. LayoutManager2 lm = (LayoutManager2) layoutMgr;
  465. lm.invalidateLayout(this);
  466. }
  467. super.invalidate();
  468. }
  469. /**
  470. * Validates this container and all of its subcomponents.
  471. * <p>
  472. * AWT uses <code>validate</code> to cause a container to lay out
  473. * its subcomponents again after the components it contains
  474. * have been added to or modified.
  475. * @see #validate
  476. * @see Component#invalidate
  477. */
  478. public void validate() {
  479. /* Avoid grabbing lock unless really necessary. */
  480. if (!valid) {
  481. synchronized (getTreeLock()) {
  482. if (!valid && peer != null) {
  483. ContainerPeer p = null;
  484. if (peer instanceof ContainerPeer) {
  485. p = (ContainerPeer) peer;
  486. }
  487. if (p != null) {
  488. p.beginValidate();
  489. }
  490. validateTree();
  491. valid = true;
  492. if (p != null) {
  493. p.endValidate();
  494. }
  495. }
  496. }
  497. }
  498. }
  499. /**
  500. * Recursively descends the container tree and recomputes the
  501. * layout for any subtrees marked as needing it (those marked as
  502. * invalid). Synchronization should be provided by the method
  503. * that calls this one: <code>validate</code>.
  504. */
  505. protected void validateTree() {
  506. if (!valid) {
  507. doLayout();
  508. Component component[] = this.component;
  509. for (int i = 0 ; i < ncomponents ; ++i) {
  510. Component comp = component[i];
  511. if ( (comp instanceof Container)
  512. && !(comp instanceof Window)
  513. && !comp.valid) {
  514. ((Container)comp).validateTree();
  515. } else {
  516. comp.validate();
  517. }
  518. }
  519. }
  520. valid = true;
  521. }
  522. /**
  523. * Recursively descends the container tree and invalidates all
  524. * contained components.
  525. */
  526. void invalidateTree() {
  527. synchronized (getTreeLock()) {
  528. for (int i = 0; i < ncomponents; ++i) {
  529. Component comp = component[i];
  530. if (comp instanceof Container) {
  531. ((Container)comp).invalidateTree();
  532. }
  533. else {
  534. if (comp.valid) {
  535. comp.invalidate();
  536. }
  537. }
  538. }
  539. if (valid) {
  540. invalidate();
  541. }
  542. }
  543. }
  544. /**
  545. * Sets the font of this container.
  546. * @param f The font to become this container's font.
  547. * @see Component#getFont
  548. * @since JDK1.0
  549. */
  550. public void setFont(Font f) {
  551. boolean shouldinvalidate = false;
  552. synchronized (this) {
  553. Font oldfont = getFont();
  554. super.setFont(f);
  555. Font newfont = getFont();
  556. if (newfont != oldfont && (oldfont == null ||
  557. !oldfont.equals(newfont))) {
  558. shouldinvalidate = true;
  559. }
  560. }
  561. if (shouldinvalidate) {
  562. invalidateTree();
  563. }
  564. }
  565. /**
  566. * Returns the preferred size of this container.
  567. * @return an instance of <code>Dimension</code> that represents
  568. * the preferred size of this container.
  569. * @see java.awt.Container#getMinimumSize
  570. * @see java.awt.Container#getLayout
  571. * @see java.awt.LayoutManager#preferredLayoutSize(java.awt.Container)
  572. * @see java.awt.Component#getPreferredSize
  573. */
  574. public Dimension getPreferredSize() {
  575. return preferredSize();
  576. }
  577. /**
  578. * @deprecated As of JDK version 1.1,
  579. * replaced by <code>getPreferredSize()</code>.
  580. */
  581. public Dimension preferredSize() {
  582. /* Avoid grabbing the lock if a reasonable cached size value
  583. * is available.
  584. */
  585. Dimension dim = prefSize;
  586. if (dim != null && isValid()) {
  587. return dim;
  588. }
  589. synchronized (getTreeLock()) {
  590. prefSize = (layoutMgr != null) ?
  591. layoutMgr.preferredLayoutSize(this) :
  592. super.preferredSize();
  593. return prefSize;
  594. }
  595. }
  596. /**
  597. * Returns the minimum size of this container.
  598. * @return an instance of <code>Dimension</code> that represents
  599. * the minimum size of this container.
  600. * @see java.awt.Container#getPreferredSize
  601. * @see java.awt.Container#getLayout
  602. * @see java.awt.LayoutManager#minimumLayoutSize(java.awt.Container)
  603. * @see java.awt.Component#getMinimumSize
  604. * @since JDK1.1
  605. */
  606. public Dimension getMinimumSize() {
  607. return minimumSize();
  608. }
  609. /**
  610. * @deprecated As of JDK version 1.1,
  611. * replaced by <code>getMinimumSize()</code>.
  612. */
  613. public Dimension minimumSize() {
  614. /* Avoid grabbing the lock if a reasonable cached size value
  615. * is available.
  616. */
  617. Dimension dim = minSize;
  618. if (dim != null && isValid()) {
  619. return dim;
  620. }
  621. synchronized (getTreeLock()) {
  622. minSize = (layoutMgr != null) ?
  623. layoutMgr.minimumLayoutSize(this) :
  624. super.minimumSize();
  625. return minSize;
  626. }
  627. }
  628. /**
  629. * Returns the maximum size of this container.
  630. * @see #getPreferredSize
  631. */
  632. public Dimension getMaximumSize() {
  633. /* Avoid grabbing the lock if a reasonable cached size value
  634. * is available.
  635. */
  636. Dimension dim = maxSize;
  637. if (dim != null && isValid()) {
  638. return dim;
  639. }
  640. if (layoutMgr instanceof LayoutManager2) {
  641. synchronized (getTreeLock()) {
  642. LayoutManager2 lm = (LayoutManager2) layoutMgr;
  643. maxSize = lm.maximumLayoutSize(this);
  644. }
  645. } else {
  646. maxSize = super.getMaximumSize();
  647. }
  648. return maxSize;
  649. }
  650. /**
  651. * Returns the alignment along the x axis. This specifies how
  652. * the component would like to be aligned relative to other
  653. * components. The value should be a number between 0 and 1
  654. * where 0 represents alignment along the origin, 1 is aligned
  655. * the furthest away from the origin, 0.5 is centered, etc.
  656. */
  657. public float getAlignmentX() {
  658. float xAlign;
  659. if (layoutMgr instanceof LayoutManager2) {
  660. synchronized (getTreeLock()) {
  661. LayoutManager2 lm = (LayoutManager2) layoutMgr;
  662. xAlign = lm.getLayoutAlignmentX(this);
  663. }
  664. } else {
  665. xAlign = super.getAlignmentX();
  666. }
  667. return xAlign;
  668. }
  669. /**
  670. * Returns the alignment along the y axis. This specifies how
  671. * the component would like to be aligned relative to other
  672. * components. The value should be a number between 0 and 1
  673. * where 0 represents alignment along the origin, 1 is aligned
  674. * the furthest away from the origin, 0.5 is centered, etc.
  675. */
  676. public float getAlignmentY() {
  677. float yAlign;
  678. if (layoutMgr instanceof LayoutManager2) {
  679. synchronized (getTreeLock()) {
  680. LayoutManager2 lm = (LayoutManager2) layoutMgr;
  681. yAlign = lm.getLayoutAlignmentY(this);
  682. }
  683. } else {
  684. yAlign = super.getAlignmentY();
  685. }
  686. return yAlign;
  687. }
  688. /**
  689. * Paints the container. This forwards the paint to any lightweight components
  690. * that are children of this container. If this method is reimplemented,
  691. * super.paint(g) should be called so that lightweight components are properly
  692. * rendered. If a child component is entirely clipped by the current clipping
  693. * setting in g, paint() will not be forwarded to that child.
  694. *
  695. * @param g the specified Graphics window
  696. * @see java.awt.Component#update(java.awt.Graphics)
  697. */
  698. public void paint(Graphics g) {
  699. if (isShowing()) {
  700. int ncomponents = this.ncomponents;
  701. Component component[] = this.component;
  702. Rectangle clip = g.getClipRect();
  703. for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  704. Component comp = component[i];
  705. if (comp != null &&
  706. comp.peer instanceof java.awt.peer.LightweightPeer &&
  707. comp.visible == true) {
  708. Rectangle cr = comp.getBounds();
  709. if (( clip == null ) || cr.intersects(clip)) {
  710. Graphics cg = g.create(cr.x, cr.y, cr.width, cr.height);
  711. cg.setFont(comp.getFont());
  712. try {
  713. comp.paint(cg);
  714. } finally {
  715. cg.dispose();
  716. }
  717. }
  718. }
  719. }
  720. }
  721. }
  722. /**
  723. * Updates the container. This forwards the update to any lightweight components
  724. * that are children of this container. If this method is reimplemented,
  725. * super.update(g) should be called so that lightweight components are properly
  726. * rendered. If a child component is entirely clipped by the current clipping
  727. * setting in g, update() will not be forwarded to that child.
  728. *
  729. * @param g the specified Graphics window
  730. * @see java.awt.Component#update(java.awt.Graphics)
  731. */
  732. public void update(Graphics g) {
  733. if (isShowing()) {
  734. if (! (peer instanceof java.awt.peer.LightweightPeer)) {
  735. g.clearRect(0, 0, width, height);
  736. }
  737. paint(g);
  738. }
  739. }
  740. /**
  741. * Prints the container. This forwards the print to any lightweight components
  742. * that are children of this container. If this method is reimplemented,
  743. * super.print(g) should be called so that lightweight components are properly
  744. * rendered. If a child component is entirely clipped by the current clipping
  745. * setting in g, print() will not be forwarded to that child.
  746. *
  747. * @param g the specified Graphics window
  748. * @see java.awt.Component#update(java.awt.Graphics)
  749. */
  750. public void print(Graphics g) {
  751. super.print(g); // By default, Component.print() calls paint()
  752. int ncomponents = this.ncomponents;
  753. Component component[] = this.component;
  754. Rectangle clip = g.getClipRect();
  755. for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  756. Component comp = component[i];
  757. if (comp != null &&
  758. comp.peer instanceof java.awt.peer.LightweightPeer) {
  759. Rectangle cr = comp.getBounds();
  760. if ((clip == null) || cr.intersects(clip)) {
  761. Graphics cg = g.create(cr.x, cr.y, cr.width, cr.height);
  762. try {
  763. comp.print(cg);
  764. } finally {
  765. cg.dispose();
  766. }
  767. }
  768. }
  769. }
  770. }
  771. /**
  772. * Paints each of the components in this container.
  773. * @param g the graphics context.
  774. * @see java.awt.Component#paint
  775. * @see java.awt.Component#paintAll
  776. */
  777. public void paintComponents(Graphics g) {
  778. int ncomponents = this.ncomponents;
  779. Component component[] = this.component;
  780. for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  781. Component comp = component[i];
  782. if (comp != null) {
  783. Graphics cg = comp.getGraphics();
  784. if (cg != null) {
  785. Rectangle parentRect = g.getClipRect();
  786. // Calculate the clipping region of the child's graphics
  787. // context, by taking the intersection of the parent's
  788. // clipRect (if any) and the child's bounds, and then
  789. // translating it's coordinates to be relative to the
  790. // child.
  791. if (parentRect != null) {
  792. Rectangle childRect = comp.getBounds();
  793. if (childRect.intersects(parentRect) == false) {
  794. // Child component is completely clipped out:
  795. // ignore.
  796. continue;
  797. }
  798. Rectangle childClipRect =
  799. childRect.intersection(parentRect);
  800. childClipRect.translate(-childRect.x, -childRect.y);
  801. cg.clipRect(childClipRect.x, childClipRect.y,
  802. childClipRect.width, childClipRect.height);
  803. }
  804. try {
  805. comp.paintAll(cg);
  806. } finally {
  807. cg.dispose();
  808. }
  809. }
  810. }
  811. }
  812. }
  813. /**
  814. * Prints each of the components in this container.
  815. * @param g the graphics context.
  816. * @see java.awt.Component#print
  817. * @see java.awt.Component#printAll
  818. */
  819. public void printComponents(Graphics g) {
  820. int ncomponents = this.ncomponents;
  821. Component component[] = this.component;
  822. // A seriously sad hack--
  823. // Lightweight components always paint behind peered components,
  824. // even if they are at the top of the Z order. We emulate this
  825. // behavior by making two printing passes: the first for lightweights;
  826. // the second for heavyweights.
  827. for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  828. Component comp = component[i];
  829. if (comp != null &&
  830. comp.peer instanceof java.awt.peer.LightweightPeer) {
  831. printOneComponent(g, comp);
  832. }
  833. }
  834. for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  835. Component comp = component[i];
  836. if (comp != null &&
  837. !(comp.peer instanceof java.awt.peer.LightweightPeer)) {
  838. printOneComponent(g, comp);
  839. }
  840. }
  841. }
  842. private void printOneComponent(Graphics g, Component comp) {
  843. Graphics cg = g.create(comp.x, comp.y, comp.width,
  844. comp.height);
  845. cg.setFont(comp.getFont());
  846. try {
  847. comp.printAll(cg);
  848. } finally {
  849. cg.dispose();
  850. }
  851. }
  852. /**
  853. * Simulates the peer callbacks into java.awt for printing of
  854. * lightweight Containers.
  855. * @param g the graphics context to use for printing.
  856. * @see Component#printAll
  857. * @see #printComponents
  858. */
  859. void lightweightPrint(Graphics g) {
  860. super.lightweightPrint(g);
  861. printHeavyweightComponents(g);
  862. }
  863. /**
  864. * Prints all the heavyweight subcomponents.
  865. */
  866. void printHeavyweightComponents(Graphics g) {
  867. int ncomponents = this.ncomponents;
  868. Component component[] = this.component;
  869. for (int i = ncomponents - 1 ; i >= 0 ; i--) {
  870. Component comp = component[i];
  871. if (comp != null) {
  872. if (!(comp.peer instanceof java.awt.peer.LightweightPeer)) {
  873. printOneComponent(g, comp);
  874. } else {
  875. Graphics cg = g.create(comp.x, comp.y,
  876. comp.width, comp.height);
  877. cg.setFont(comp.getFont());
  878. try {
  879. comp.printHeavyweightComponents(cg);
  880. } finally {
  881. cg.dispose();
  882. }
  883. }
  884. }
  885. }
  886. }
  887. /**
  888. * Adds the specified container listener to receive container events
  889. * from this container.
  890. * If l is null, no exception is thrown and no action is performed.
  891. *
  892. * @param l the container listener
  893. */
  894. public synchronized void addContainerListener(ContainerListener l) {
  895. if (l == null) {
  896. return;
  897. }
  898. containerListener = AWTEventMulticaster.add(containerListener, l);
  899. newEventsOnly = true;
  900. }
  901. /**
  902. * Removes the specified container listener so it no longer receives
  903. * container events from this container.
  904. * If l is null, no exception is thrown and no action is performed.
  905. *
  906. * @param l the container listener
  907. */
  908. public synchronized void removeContainerListener(ContainerListener l) {
  909. if (l == null) {
  910. return;
  911. }
  912. containerListener = AWTEventMulticaster.remove(containerListener, l);
  913. }
  914. // REMIND: remove when filtering is done at lower level
  915. boolean eventEnabled(AWTEvent e) {
  916. int id = e.getID();
  917. if (id == ContainerEvent.COMPONENT_ADDED ||
  918. id == ContainerEvent.COMPONENT_REMOVED) {
  919. if ((eventMask & AWTEvent.CONTAINER_EVENT_MASK) != 0 ||
  920. containerListener != null) {
  921. return true;
  922. }
  923. return false;
  924. }
  925. return super.eventEnabled(e);
  926. }
  927. /**
  928. * Processes events on this container. If the event is a ContainerEvent,
  929. * it invokes the processContainerEvent method, else it invokes its
  930. * superclass's processEvent.
  931. * @param e the event
  932. */
  933. protected void processEvent(AWTEvent e) {
  934. if (e instanceof ContainerEvent) {
  935. processContainerEvent((ContainerEvent)e);
  936. return;
  937. }
  938. super.processEvent(e);
  939. }
  940. /**
  941. * Processes container events occurring on this container by
  942. * dispatching them to any registered ContainerListener objects.
  943. * NOTE: This method will not be called unless container events
  944. * are enabled for this component; this happens when one of the
  945. * following occurs:
  946. * a) A ContainerListener object is registered via addContainerListener()
  947. * b) Container events are enabled via enableEvents()
  948. * @see Component#enableEvents
  949. * @param e the container event
  950. */
  951. protected void processContainerEvent(ContainerEvent e) {
  952. if (containerListener != null) {
  953. switch(e.getID()) {
  954. case ContainerEvent.COMPONENT_ADDED:
  955. containerListener.componentAdded(e);
  956. break;
  957. case ContainerEvent.COMPONENT_REMOVED:
  958. containerListener.componentRemoved(e);
  959. break;
  960. }
  961. }
  962. }
  963. /*
  964. * Dispatches an event to this component or one of its sub components.
  965. * @param e the event
  966. */
  967. void dispatchEventImpl(AWTEvent e) {
  968. if ((dispatcher != null) && dispatcher.dispatchEvent(e)) {
  969. // event was sent to a lightweight component. The
  970. // native-produced event sent to the native container
  971. // must be properly disposed of by the peer, so it
  972. // gets forwarded. If the native host has been removed
  973. // as a result of the sending the lightweight event,
  974. // the peer reference will be null.
  975. e.consume();
  976. if (peer != null) {
  977. peer.handleEvent(e);
  978. }
  979. return;
  980. }
  981. super.dispatchEventImpl(e);
  982. }
  983. /*
  984. * Dispatches an event to this component, without trying to forward
  985. * it to any sub components
  986. * @param e the event
  987. */
  988. void dispatchEventToSelf(AWTEvent e) {
  989. super.dispatchEventImpl(e);
  990. }
  991. /**
  992. * Fetchs the top-most (deepest) lightweight component that is interested
  993. * in receiving mouse events.
  994. */
  995. Component getMouseEventTarget(int x, int y, boolean includeSelf) {
  996. int ncomponents = this.ncomponents;
  997. Component component[] = this.component;
  998. for (int i = 0 ; i < ncomponents ; i++) {
  999. Component comp = component[i];
  1000. if ((comp != null) && (comp.contains(x - comp.x, y - comp.y)) &&
  1001. (comp.peer instanceof java.awt.peer.LightweightPeer) &&
  1002. (comp.visible == true)) {
  1003. // found a component that intersects the point, see if there is
  1004. // a deeper possibility.
  1005. if (comp instanceof Container) {
  1006. Container child = (Container) comp;
  1007. Component deeper = child.getMouseEventTarget(x - child.x, y - child.y, includeSelf);
  1008. if (deeper != null) {
  1009. return deeper;
  1010. }
  1011. } else {
  1012. if ((comp.mouseListener != null) ||
  1013. ((comp.eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0) ||
  1014. (comp.mouseMotionListener != null) ||
  1015. ((comp.eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0)) {
  1016. // there isn't a deeper target, but this component is a target
  1017. return comp;
  1018. }
  1019. }
  1020. }
  1021. }
  1022. boolean isPeerOK;
  1023. boolean isMouseOverMe;
  1024. boolean isMouseListener;
  1025. boolean isMotionListener;
  1026. isPeerOK = (peer instanceof java.awt.peer.LightweightPeer) || includeSelf;
  1027. isMouseOverMe = contains(x,y);
  1028. isMouseListener = (mouseListener != null) ||
  1029. ((eventMask & AWTEvent.MOUSE_EVENT_MASK) != 0);
  1030. isMotionListener = (mouseMotionListener != null) ||
  1031. ((eventMask & AWTEvent.MOUSE_MOTION_EVENT_MASK) != 0);
  1032. // didn't find a child target, return this component if it's a possible target
  1033. if ( isMouseOverMe && isPeerOK && (isMouseListener || isMotionListener) ) {
  1034. return this;
  1035. }
  1036. // no possible target
  1037. return null;
  1038. }
  1039. /*
  1040. * Set the cursor image to a predefined cursor.
  1041. * @param <code>cursor</code> One of the constants defined
  1042. * by the <code>Cursor</code> class.
  1043. * @see java.awt.Component#getCursor
  1044. * @see java.awt.Cursor
  1045. * @since JDK1.1
  1046. */
  1047. public synchronized void setCursor(Cursor cursor) {
  1048. if (dispatcher != null) {
  1049. Component cursorOn = dispatcher.getCursorOn();
  1050. // if mouse is on a lightweight component, we should not
  1051. // call setCursor on the nativeContainer
  1052. if (cursorOn != null) {
  1053. this.cursor = cursor;
  1054. // it could be that cursorOn will inherit cursor
  1055. dispatcher.updateCursor(cursorOn);
  1056. return;
  1057. }
  1058. }
  1059. super.setCursor(cursor);
  1060. }
  1061. /**
  1062. * Update the cursor is decided by the dispatcher
  1063. * This method is used when setCursor on a lightweight
  1064. */
  1065. void updateCursor(Component comp) {
  1066. if (dispatcher != null) {
  1067. dispatcher.updateCursor(comp);
  1068. }
  1069. }
  1070. /**
  1071. * Fetchs the top-most (deepest) lightweight component whose cursor
  1072. * should be displayed.
  1073. */
  1074. Component getCursorTarget(int x, int y) {
  1075. int ncomponents = this.ncomponents;
  1076. Component component[] = this.component;
  1077. for (int i = 0 ; i < ncomponents ; i++) {
  1078. Component comp = component[i];
  1079. if ((comp != null) && (comp.contains(x - comp.x, y - comp.y)) &&
  1080. (comp.visible == true)) {
  1081. // found a component that intersects the point, see if there is
  1082. // a deeper possibility.
  1083. if (comp instanceof Container) {
  1084. Container child = (Container) comp;
  1085. Component deeper = child.getCursorTarget(x - child.x, y - child.y);
  1086. if (deeper != null) {
  1087. return deeper;
  1088. }
  1089. } else {
  1090. return comp;
  1091. }
  1092. }
  1093. }
  1094. if (contains(x,y) && (peer instanceof java.awt.peer.LightweightPeer)) {
  1095. return this;
  1096. }
  1097. // no possible target
  1098. return null;
  1099. }
  1100. /**
  1101. * This is called by lightweight components that want the containing
  1102. * windowed parent to enable some kind of events on their behalf.
  1103. * This is needed for events that are normally only dispatched to
  1104. * windows to be accepted so that they can be forwarded downward to
  1105. * the lightweight component that has enabled them.
  1106. */
  1107. void proxyEnableEvents(long events) {
  1108. if (peer instanceof java.awt.peer.LightweightPeer) {
  1109. // this container is lightweight.... continue sending it
  1110. // upward.
  1111. parent.proxyEnableEvents(events);
  1112. } else {
  1113. // This is a native container, so it needs to host
  1114. // one of it's children. If this function is called before
  1115. // a peer has been created we don't yet have a dispatcher
  1116. // because it has not yet been determined if this instance
  1117. // is lightweight.
  1118. if (dispatcher != null) {
  1119. dispatcher.enableEvents(events);
  1120. }
  1121. }
  1122. }
  1123. Window getWindow() {
  1124. Container w = this;
  1125. while( !(w instanceof Window) ) {
  1126. w = w.getParent();
  1127. }
  1128. return (Window)w;
  1129. }
  1130. /**
  1131. * This is called by lightweight components that have requested focus.
  1132. * The focus request is propagated upward until a native container is
  1133. * found, at which point the native container requests focus and records
  1134. * the component the host is requesting focus for.
  1135. */
  1136. void proxyRequestFocus(Component c) {
  1137. if (peer instanceof java.awt.peer.LightweightPeer) {
  1138. // this container is lightweight... continue sending it
  1139. // upward.
  1140. parent.proxyRequestFocus(c);
  1141. } else {
  1142. // This is a windowed container, so record true focus
  1143. // component and request focus from the native window
  1144. // if needed.
  1145. if (dispatcher.setFocusRequest(c)) {
  1146. // If the focus is currently somewhere within this Window,
  1147. // call the peer to set focus to this Container. This way,
  1148. // we avoid activating this Window if it's not currently
  1149. // active. -fredx, 2-19-98, bug #4111098
  1150. Component window = this;
  1151. while (!(window instanceof Window))
  1152. window = window.getParent();
  1153. if (((Window)window).isActive() ||
  1154. ! (window instanceof Frame || window instanceof Dialog) ) {
  1155. peer.requestFocus();
  1156. }
  1157. Toolkit.getEventQueue().changeKeyEventFocus(this);
  1158. }
  1159. }
  1160. }
  1161. /**
  1162. * @deprecated As of JDK version 1.1,
  1163. * replaced by <code>dispatchEvent(AWTEvent e)</code>
  1164. */
  1165. public void deliverEvent(Event e) {
  1166. Component comp = getComponentAt(e.x, e.y);
  1167. if ((comp != null) && (comp != this)) {
  1168. e.translate(-comp.x, -comp.y);
  1169. comp.deliverEvent(e);
  1170. } else {
  1171. postEvent(e);
  1172. }
  1173. }
  1174. /**
  1175. * Locates the component that contains the x,y position. The
  1176. * top-most child component is returned in the case where there
  1177. * is overlap in the components. This is determined by finding
  1178. * the component closest to the index 0 that claims to contain
  1179. * the given point via Component.contains().
  1180. * @param x the <i>x</i> coordinate
  1181. * @param y the <i>y</i> coordinate
  1182. * @return null if the component does not contain the position.
  1183. * If there is no child component at the requested point and the
  1184. * point is within the bounds of the container the container itself
  1185. * is returned; otherwise the top-most child is returned.
  1186. * @see Component#contains
  1187. * @since JDK1.1
  1188. */
  1189. public Component getComponentAt(int x, int y) {
  1190. return locate(x, y);
  1191. }
  1192. /**
  1193. * @deprecated As of JDK version 1.1,
  1194. * replaced by <code>getComponentAt(int, int)</code>.
  1195. */
  1196. public Component locate(int x, int y) {
  1197. if (!contains(x, y)) {
  1198. return null;
  1199. }
  1200. int ncomponents = this.ncomponents;
  1201. Component component[] = this.component;
  1202. for (int i = 0 ; i < ncomponents ; i++) {
  1203. Component comp = component[i];
  1204. if (comp != null) {
  1205. if (comp.contains(x - comp.x, y - comp.y)) {
  1206. return comp;
  1207. }
  1208. }
  1209. }
  1210. return this;
  1211. }
  1212. /**
  1213. * Gets the component that contains the specified point.
  1214. * @param p the point.
  1215. * @return returns the component that contains the point,
  1216. * or <code>null</code> if the component does
  1217. * not contain the point.
  1218. * @see java.awt.Component#contains
  1219. * @since JDK1.1
  1220. */
  1221. public Component getComponentAt(Point p) {
  1222. return getComponentAt(p.x, p.y);
  1223. }
  1224. /**
  1225. * Locates the visible child component that contains the specified
  1226. * position. The top-most child component is returned in the case
  1227. * where there is overlap in the components. If the containing child
  1228. * component is a Container, this method will continue searching for
  1229. * the deepest nested child component. Components which are not
  1230. * visible are ignored during the search.<p>
  1231. *
  1232. * The findComponentAt method is different from getComponentAt in
  1233. * that getComponentAt only searches the Container's immediate
  1234. * children; if the containing component is a Container,
  1235. * findComponentAt will search that child to find a nested component.
  1236. *
  1237. * @param x the <i>x</i> coordinate
  1238. * @param y the <i>y</i> coordinate
  1239. * @return null if the component does not contain the position.
  1240. * If there is no child component at the requested point and the
  1241. * point is within the bounds of the container the container itself
  1242. * is returned.
  1243. * @see Component#contains
  1244. * @see getComponentAt
  1245. * @since JDK1.2
  1246. */
  1247. public Component findComponentAt(int x, int y) {
  1248. if (!contains(x, y)) {
  1249. return null;
  1250. }
  1251. int ncomponents = this.ncomponents;
  1252. Component component[] = this.component;
  1253. for (int i = 0 ; i < ncomponents ; i++) {
  1254. Component comp = component[i];
  1255. if (comp != null) {
  1256. if (comp instanceof Container) {
  1257. comp = ((Container)comp).findComponentAt(x - comp.x,
  1258. y - comp.y);
  1259. } else {
  1260. comp = comp.locate(x - comp.x, y - comp.y);
  1261. }
  1262. if (comp != null && comp.isVisible()) {
  1263. return comp;
  1264. }
  1265. }
  1266. }
  1267. return this;
  1268. }
  1269. /**
  1270. * Locates the visible child component that contains the specified
  1271. * point. The top-most child component is returned in the case
  1272. * where there is overlap in the components. If the containing child
  1273. * component is a Container, this method will continue searching for
  1274. * the deepest nested child component. Components which are not
  1275. * visible are ignored during the search.<p>
  1276. *
  1277. * The findComponentAt method is different from getComponentAt in
  1278. * that getComponentAt only searches the Container's immediate
  1279. * children; if the containing component is a Container,
  1280. * findComponentAt will search that child to find a nested component.
  1281. *
  1282. * @param p the point.
  1283. * @return null if the component does not contain the position.
  1284. * If there is no child component at the requested point and the
  1285. * point is within the bounds of the container the container itself
  1286. * is returned.
  1287. * @see Component#contains
  1288. * @see getComponentAt
  1289. * @since JDK1.2
  1290. */
  1291. public Component findComponentAt(Point p) {
  1292. return findComponentAt(p.x, p.y);
  1293. }
  1294. /**
  1295. * Makes this Container displayable by connecting it to
  1296. * a native screen resource. Making a container displayable will
  1297. * cause any of its children to be made displayable.
  1298. * This method is called internally by the toolkit and should
  1299. * not be called directly by programs.
  1300. * @see Component#isDisplayable
  1301. * @see #removeNotify
  1302. */
  1303. public void addNotify() {
  1304. synchronized (getTreeLock()) {
  1305. // addNotify() on the children may cause proxy event enabling
  1306. // on this instance, so we first call super.addNotify() and
  1307. // possibly create an lightweight event dispatcher before calling
  1308. // addNotify() on the children which may be lightweight.
  1309. super.addNotify();
  1310. if (! (peer instanceof java.awt.peer.LightweightPeer)) {
  1311. dispatcher = new LightweightDispatcher(this);
  1312. }
  1313. int ncomponents = this.ncomponents;
  1314. Component component[] = this.component;
  1315. for (int i = 0 ; i < ncomponents ; i++) {
  1316. component[i].addNotify();
  1317. }
  1318. }
  1319. }
  1320. /**
  1321. * Makes this Container undisplayable by removing its connection
  1322. * to its native screen resource. Make a container undisplayable
  1323. * will cause any of its children to be made undisplayable.
  1324. * This method is called by the toolkit internally and should
  1325. * not be called directly by programs.
  1326. * @see Component#isDisplayable
  1327. * @see #addNotify
  1328. */
  1329. public void removeNotify() {
  1330. synchronized (getTreeLock()) {
  1331. int ncomponents = this.ncomponents;
  1332. Component component[] = this.component;
  1333. for (int i = 0 ; i < ncomponents ; i++) {
  1334. component[i].removeNotify();
  1335. }
  1336. if ( dispatcher != null ) {
  1337. dispatcher.dispose();
  1338. }
  1339. super.removeNotify();
  1340. }
  1341. }
  1342. /**
  1343. * Checks if the component is contained in the component hierarchy of
  1344. * this container.
  1345. * @param c the component
  1346. * @return <code>true</code> if it is an ancestor;
  1347. * <code>false</code> otherwise.
  1348. * @since JDK1.1
  1349. */
  1350. public boolean isAncestorOf(Component c) {
  1351. Container p;
  1352. if (c == null || ((p = c.getParent()) == null)) {
  1353. return false;
  1354. }
  1355. while (p != null) {
  1356. if (p == this) {
  1357. return true;
  1358. }
  1359. p = p.getParent();
  1360. }
  1361. return false;
  1362. }
  1363. /**
  1364. * Returns the parameter string representing the state of this
  1365. * container. This string is useful for debugging.
  1366. * @return the parameter string of this container.
  1367. */
  1368. protected String paramString() {
  1369. String str = super.paramString();
  1370. LayoutManager layoutMgr = this.layoutMgr;
  1371. if (layoutMgr != null) {
  1372. str += ",layout=" + layoutMgr.getClass().getName();
  1373. }
  1374. return str;
  1375. }
  1376. /**
  1377. * Prints a listing of this container to the specified output
  1378. * stream. The listing starts at the specified indentation.
  1379. * @param out a print stream.
  1380. * @param indent the number of spaces to indent.
  1381. * @see java.awt.Component#list(java.io.PrintStream, int)
  1382. * @since JDK
  1383. */
  1384. public void list(PrintStream out, int indent) {
  1385. super.list(out, indent);
  1386. int ncomponents = this.ncomponents;
  1387. Component component[] = this.component;
  1388. for (int i = 0 ; i < ncomponents ; i++) {
  1389. Component comp = component[i];
  1390. if (comp != null) {
  1391. comp.list(out, indent+1);
  1392. }
  1393. }
  1394. }
  1395. /**
  1396. * Prints out a list, starting at the specified indention, to the specified
  1397. * print writer.
  1398. */
  1399. public void list(PrintWriter out, int indent) {
  1400. super.list(out, indent);
  1401. int ncomponents = this.ncomponents;
  1402. Component component[] = this.component;
  1403. for (int i = 0 ; i < ncomponents ; i++) {
  1404. Component comp = component[i];
  1405. if (comp != null) {
  1406. comp.list(out, indent+1);
  1407. }
  1408. }
  1409. }
  1410. void setFocusOwner(Component c) {
  1411. Container parent = this.parent;
  1412. if (parent != null) {
  1413. parent.setFocusOwner(c);
  1414. }
  1415. }
  1416. void preProcessKeyEvent(KeyEvent e) {
  1417. Container parent = this.parent;
  1418. if (parent != null) {
  1419. parent.preProcessKeyEvent(e);
  1420. }
  1421. }
  1422. void postProcessKeyEvent(KeyEvent e) {
  1423. Container parent = this.parent;
  1424. if (parent != null) {
  1425. parent.postProcessKeyEvent(e);
  1426. }
  1427. }
  1428. void transferFocus(Component base) {
  1429. nextFocus(base);
  1430. }
  1431. boolean postsOldMouseEvents() {
  1432. return true;
  1433. }
  1434. /**
  1435. * @deprecated As of JDK version 1.1,
  1436. * replaced by transferFocus(Component).
  1437. */
  1438. void nextFocus(Component base) {
  1439. Container parent = this.parent;
  1440. if (parent != null) {
  1441. parent.transferFocus(base);
  1442. }
  1443. }
  1444. /**
  1445. * Package-visible utility to set the orientation of this container
  1446. * and all components contained within it.
  1447. * @since JDK1.2
  1448. * @see java.awt.Window#applyResourceBundle(java.util.ResourceBundle)
  1449. */
  1450. void applyOrientation(ComponentOrientation o) {
  1451. setComponentOrientation(o);
  1452. for (int i = 0 ; i < ncomponents ; ++i) {
  1453. Component comp = component[i];
  1454. if (comp instanceof Container) {
  1455. ((Container)comp).applyOrientation(o);
  1456. } else {
  1457. comp.setComponentOrientation(o);
  1458. }
  1459. }
  1460. }
  1461. /* Serialization support. A Container is responsible for
  1462. * restoring the parent fields of its component children.
  1463. */
  1464. /*
  1465. * Container Serial Data Version.
  1466. * @serial
  1467. */
  1468. private int containerSerializedDataVersion = 1;
  1469. /**
  1470. * Writes default serializable fields to stream. Writes
  1471. * a list of serializable ItemListener(s) as optional data.
  1472. * The non-serializable ItemListner(s) are detected and
  1473. * no attempt is made to serialize them.
  1474. *
  1475. * @serialData Null terminated sequence of 0 or more pairs.
  1476. * The pair consists of a String and Object.
  1477. * The String indicates the type of object and
  1478. * is one of the following :
  1479. * itemListenerK indicating and ItemListener object.
  1480. *
  1481. * @see AWTEventMulticaster.save(ObjectOutputStream, String, EventListener)
  1482. * @see java.awt.Component.itemListenerK
  1483. */
  1484. private void writeObject(ObjectOutputStream s)
  1485. throws IOException
  1486. {
  1487. s.defaultWriteObject();
  1488. AWTEventMulticaster.save(s, containerListenerK, containerListener);
  1489. s.writeObject(null);
  1490. }
  1491. /*
  1492. * Read the ObjectInputStream and if it isnt null
  1493. * add a listener to receive item events fired
  1494. * by the component in the container.
  1495. * Unrecognised keys or values will be Ignored.
  1496. * @serial
  1497. * @see removeActionListener()
  1498. * @see addActionListener()
  1499. */
  1500. private void readObject(ObjectInputStream s)
  1501. throws ClassNotFoundException, IOException
  1502. {
  1503. s.defaultReadObject();
  1504. Component component[] = this.component;
  1505. for(int i = 0; i < ncomponents; i++)
  1506. component[i].parent = this;
  1507. Object keyOrNull;
  1508. while(null != (keyOrNull = s.readObject())) {
  1509. String key = ((String)keyOrNull).intern();
  1510. if (containerListenerK == key)
  1511. addContainerListener((ContainerListener)(s.readObject()));
  1512. else // skip value for unrecognized key
  1513. s.readObject();
  1514. }
  1515. }
  1516. }
  1517. /**
  1518. * Class to manage the dispatching of events to the lightweight
  1519. * components contained by a native container.
  1520. *
  1521. * @author Timothy Prinzing
  1522. */
  1523. class LightweightDispatcher implements java.io.Serializable, AWTEventListener {
  1524. /*
  1525. * JDK 1.1 serialVersionUID
  1526. */
  1527. private static final long serialVersionUID = 5184291520170872969L;
  1528. /*
  1529. * Our own mouse event for when we're dragged over from another hw container
  1530. */
  1531. private static final int LWD_MOUSE_DRAGGED_OVER = AWTEvent.RESERVED_ID_MAX + 1;
  1532. LightweightDispatcher(Container nativeContainer) {
  1533. this.nativeContainer = nativeContainer;
  1534. focus = null;
  1535. mouseEventTarget = null;
  1536. eventMask = 0;
  1537. }
  1538. /*
  1539. * Clean up any resources allocated when dispatcher was created;
  1540. * should be called from Container.removeNotify
  1541. */
  1542. void dispose() {
  1543. //System.out.println("Disposing lw dispatcher");
  1544. stopListeningForOtherDrags();
  1545. }
  1546. /**
  1547. * Enables events to lightweight components.
  1548. */
  1549. void enableEvents(long events) {
  1550. eventMask |= events;
  1551. }
  1552. /**
  1553. * This is called by the hosting native container on behalf of lightweight
  1554. * components that have requested focus. The focus request is propagated
  1555. * upward from the requesting lightweight component until a windowed host
  1556. * is found, at which point the windowed host calls this method. This method
  1557. * returns whether or not the peer associated with the native component needs
  1558. * to request focus from the native window system.
  1559. *
  1560. * If a lightweight component already has focus the focus events are synthesized
  1561. * since there will be no native events to drive the focus. If the native host
  1562. * already has focus, the focus gained is synthesized for the lightweight component
  1563. * requesting focus since it will receive no native focus requests.
  1564. */
  1565. boolean setFocusRequest(Component c) {
  1566. boolean peerNeedsRequest = true;
  1567. Window w = nativeContainer.getWindow();
  1568. if (w != null && c != null) {
  1569. Component focusOwner = w.getFocusOwner();
  1570. if (focusOwner == null) {
  1571. // No focus in this component
  1572. focus = c;
  1573. } else if (focusOwner == nativeContainer) {
  1574. // This container already has focus, so just
  1575. // send a FOCUS_LOST event to the container
  1576. // and FOCUS_GAINED event to lightweight component
  1577. nativeContainer.dispatchEvent(new FocusEvent(nativeContainer, FocusEvent.FOCUS_LOST, false));
  1578. focus = c ;
  1579. c.dispatchEvent(new FocusEvent(c, FocusEvent.FOCUS_GAINED, false));
  1580. peerNeedsRequest = false;
  1581. } else if (focusOwner == c) {
  1582. // lightweight already has the focus
  1583. focus = c ;
  1584. peerNeedsRequest = false;
  1585. } else if (focusOwner == focus) {
  1586. // a lightweight component has focus currently and a new one has been
  1587. // requested. There won't be any window-system events associated with
  1588. // this so we go ahead and send FOCUS_LOST for the old and FOCUS_GAINED
  1589. // for the new.
  1590. if (focus != null) {
  1591. focus.dispatchEvent(new FocusEvent(focus,
  1592. FocusEvent.FOCUS_LOST,
  1593. false));
  1594. }
  1595. focus = c ;
  1596. c.dispatchEvent(new FocusEvent(c, FocusEvent.FOCUS_GAINED, false));
  1597. peerNeedsRequest = false;
  1598. } else {
  1599. //Fix for bug 4095214
  1600. //Paul Sheehan
  1601. focus = c;
  1602. }
  1603. }
  1604. return peerNeedsRequest;
  1605. }
  1606. /**
  1607. * Dispatches an event to a lightweight sub-component if necessary, and
  1608. * returns whether or not the event was forwarded to a lightweight
  1609. * sub-component.
  1610. *
  1611. * @param e the event
  1612. */
  1613. boolean dispatchEvent(AWTEvent e) {
  1614. boolean ret = false;
  1615. if ((eventMask & PROXY_EVENT_MASK) != 0) {
  1616. if ((e instanceof MouseEvent) &&
  1617. ((eventMask & MOUSE_MASK) != 0)) {
  1618. MouseEvent me = (MouseEvent) e;
  1619. ret = processMouseEvent(me);
  1620. } else if (e instanceof FocusEvent) {
  1621. FocusEvent fe = (FocusEvent) e;
  1622. ret = processFocusEvent(fe);
  1623. } else if (e instanceof KeyEvent) {
  1624. KeyEvent ke = (KeyEvent) e;
  1625. ret = processKeyEvent(ke);
  1626. }
  1627. }
  1628. if (e instanceof MouseEvent) {
  1629. // find out what component the mouse moved in
  1630. MouseEvent me = (MouseEvent) e;
  1631. if (me.getID() == MouseEvent.MOUSE_MOVED) {
  1632. cursorOn = nativeContainer.getCursorTarget(me.getX(), me.getY());
  1633. updateCursor(cursorOn);
  1634. }
  1635. }
  1636. return ret;
  1637. }
  1638. private boolean processKeyEvent(KeyEvent e) {
  1639. if (focus != null) {
  1640. // Don't duplicate the event here.
  1641. // The KeyEvent for LightWeightComponent is also passed to
  1642. // input methods and their native handlers. The native handlers
  1643. // require the original native event data to be attached to
  1644. // the KeyEvent.
  1645. Component source = e.getComponent();
  1646. ((AWTEvent)e).setSource(focus);
  1647. focus.dispatchEvent(e);
  1648. ((AWTEvent)e).setSource(source);
  1649. return e.isConsumed();
  1650. }
  1651. return false;
  1652. }
  1653. private boolean processFocusEvent(FocusEvent e) {
  1654. if (focus != null) {
  1655. int id = e.getID();
  1656. FocusEvent retargeted = new FocusEvent(focus, id, e.isTemporary());
  1657. ((AWTEvent)e).copyPrivateDataInto(retargeted);
  1658. focus.dispatchEvent(retargeted);
  1659. if ((id == FocusEvent.FOCUS_LOST) && (e.isTemporary() == false)) {
  1660. focus = null;
  1661. }
  1662. return true;
  1663. }
  1664. return false;
  1665. }
  1666. /**
  1667. * This method attempts to distribute a mouse event to a lightweight
  1668. * component. It tries to avoid doing any unnecessary probes down
  1669. * into the component tree to minimize the overhead of determining
  1670. * where to route the event, since mouse movement events tend to
  1671. * come in large and frequent amounts.
  1672. */
  1673. private boolean processMouseEvent(MouseEvent e) {
  1674. int id = e.getID();
  1675. Component targetOver;
  1676. Component lwOver;
  1677. targetOver = nativeContainer.getMouseEventTarget(e.getX(), e.getY(),true);
  1678. trackMouseEnterExit(targetOver, e);
  1679. if (mouseEventTarget == null) {
  1680. if ( id == MouseEvent.MOUSE_MOVED ||
  1681. id == MouseEvent.MOUSE_PRESSED ) {
  1682. lwOver = (targetOver != nativeContainer) ? targetOver : null;
  1683. setMouseTarget(lwOver,e);
  1684. }
  1685. }
  1686. if (mouseEventTarget != null) {
  1687. // we are currently forwarding to some component, check
  1688. // to see if we should continue to forward.
  1689. switch(id) {
  1690. case MouseEvent.MOUSE_DRAGGED:
  1691. if(dragging) {
  1692. retargetMouseEvent(mouseEventTarget, id, e);
  1693. }
  1694. break;
  1695. case MouseEvent.MOUSE_PRESSED:
  1696. dragging = true;
  1697. retargetMouseEvent(mouseEventTarget, id, e);
  1698. break;
  1699. case MouseEvent.MOUSE_RELEASED:
  1700. {
  1701. Component releasedTarget = mouseEventTarget;
  1702. dragging = false;
  1703. retargetMouseEvent(mouseEventTarget, id, e);
  1704. lwOver = nativeContainer.getMouseEventTarget(e.getX(), e.getY(),false);
  1705. setMouseTarget(lwOver, e);
  1706. // fix 4155217
  1707. // component was hidden or moved in user code MOUSE_RELEASED handling
  1708. isClickOrphaned = lwOver != releasedTarget;
  1709. break;
  1710. }
  1711. case MouseEvent.MOUSE_CLICKED:
  1712. if (!isClickOrphaned) {
  1713. // fix 4155217
  1714. // click event should not be redirected since component has moved or hidden
  1715. retargetMouseEvent(mouseEventTarget, id, e);
  1716. }
  1717. isClickOrphaned = false;
  1718. break;
  1719. case MouseEvent.MOUSE_ENTERED:
  1720. break;
  1721. case MouseEvent.MOUSE_EXITED:
  1722. if (!dragging) {
  1723. setMouseTarget(null, e);
  1724. }
  1725. break;
  1726. case MouseEvent.MOUSE_MOVED:
  1727. lwOver = nativeContainer.getMouseEventTarget(e.getX(), e.getY(),false);
  1728. setMouseTarget(lwOver, e);
  1729. retargetMouseEvent(mouseEventTarget, id, e);
  1730. break;
  1731. }
  1732. e.consume();
  1733. }
  1734. return e.isConsumed();
  1735. }
  1736. /**
  1737. * Change the current target of mouse events.
  1738. */
  1739. private void setMouseTarget(Component target, MouseEvent e) {
  1740. if (target != mouseEventTarget) {
  1741. //System.out.println("setMouseTarget: " + target);
  1742. mouseEventTarget = target;
  1743. }
  1744. }
  1745. /*
  1746. * Generates enter/exit events as mouse moves over lw components
  1747. * @param targetOver Target mouse is over (including native container)
  1748. * @param e Mouse event in native container
  1749. */
  1750. private void trackMouseEnterExit(Component targetOver, MouseEvent e) {
  1751. Component targetEnter = null;
  1752. int id = e.getID();
  1753. if ( id != MouseEvent.MOUSE_EXITED &&
  1754. id != MouseEvent.MOUSE_DRAGGED &&
  1755. id != LWD_MOUSE_DRAGGED_OVER &&
  1756. isMouseInNativeContainer == false ) {
  1757. // any event but an exit or drag means we're in the native container
  1758. isMouseInNativeContainer = true;
  1759. startListeningForOtherDrags();
  1760. } else if ( id == MouseEvent.MOUSE_EXITED ) {
  1761. isMouseInNativeContainer = false;
  1762. stopListeningForOtherDrags();
  1763. }
  1764. if (isMouseInNativeContainer) {
  1765. targetEnter = targetOver;
  1766. }
  1767. //System.out.println("targetEnter = " + targetEnter);
  1768. //System.out.println("targetLastEntered = " + targetLastEntered);
  1769. if (targetLastEntered == targetEnter) {
  1770. return;
  1771. }
  1772. retargetMouseEvent(targetLastEntered, MouseEvent.MOUSE_EXITED, e);
  1773. if (id == MouseEvent.MOUSE_EXITED) {
  1774. // consume native exit event if we generate one
  1775. e.consume();
  1776. }
  1777. retargetMouseEvent(targetEnter, MouseEvent.MOUSE_ENTERED, e);
  1778. if (id == MouseEvent.MOUSE_ENTERED) {
  1779. // consume native enter event if we generate one
  1780. e.consume();
  1781. }
  1782. //System.out.println("targetLastEntered: " + targetLastEntered);
  1783. targetLastEntered = targetEnter;
  1784. }
  1785. /*
  1786. * Listens to global mouse drag events so even drags originating
  1787. * from other heavyweight containers will generate enter/exit
  1788. * events in this container
  1789. */
  1790. private void startListeningForOtherDrags() {
  1791. //System.out.println("Adding AWTEventListener");
  1792. java.security.AccessController.doPrivileged(
  1793. new java.security.PrivilegedAction() {
  1794. public Object run() {
  1795. nativeContainer.getToolkit().addAWTEventListener(
  1796. LightweightDispatcher.this,
  1797. AWTEvent.MOUSE_EVENT_MASK |
  1798. AWTEvent.MOUSE_MOTION_EVENT_MASK);
  1799. return null;
  1800. }
  1801. }
  1802. );
  1803. }
  1804. private void stopListeningForOtherDrags() {
  1805. //System.out.println("Removing AWTEventListener");
  1806. java.security.AccessController.doPrivileged(
  1807. new java.security.PrivilegedAction() {
  1808. public Object run() {
  1809. nativeContainer.getToolkit().removeAWTEventListener(LightweightDispatcher.this);
  1810. return null;
  1811. }
  1812. }
  1813. );
  1814. }
  1815. /*
  1816. * (Implementation of AWTEventListener)
  1817. * Listen for drag events posted in other hw components so we can
  1818. * track enter/exit regardless of where a drag originated
  1819. */
  1820. public void eventDispatched(AWTEvent e) {
  1821. boolean isForeignDrag = (e instanceof MouseEvent) &&
  1822. (e.id == MouseEvent.MOUSE_DRAGGED) &&
  1823. (e.getSource() != nativeContainer);
  1824. if (!isForeignDrag) {
  1825. // only interested in drags from other hw components
  1826. return;
  1827. }
  1828. MouseEvent srcEvent = (MouseEvent)e;
  1829. MouseEvent me;
  1830. synchronized (nativeContainer.getTreeLock()) {
  1831. Component srcComponent = srcEvent.getComponent();
  1832. // component may have disappeared since drag event posted
  1833. // (i.e. Swing hierarchical menus)
  1834. if ( !srcComponent.isShowing() ||
  1835. !nativeContainer.isShowing() ) {
  1836. return;
  1837. }
  1838. //
  1839. // create an internal 'dragged-over' event indicating
  1840. // we are being dragged over from another hw component
  1841. //
  1842. me = new MouseEvent(nativeContainer,
  1843. LWD_MOUSE_DRAGGED_OVER,
  1844. srcEvent.getWhen(),
  1845. srcEvent.getModifiers(),
  1846. srcEvent.getX(),
  1847. srcEvent.getY(),
  1848. srcEvent.getClickCount(),
  1849. srcEvent.isPopupTrigger());
  1850. ((AWTEvent)srcEvent).copyPrivateDataInto(me);
  1851. // translate coordinates to this native container
  1852. Point ptSrcOrigin = srcComponent.getLocationOnScreen();
  1853. Point ptDstOrigin = nativeContainer.getLocationOnScreen();
  1854. me.translatePoint( ptSrcOrigin.x - ptDstOrigin.x, ptSrcOrigin.y - ptDstOrigin.y );
  1855. }
  1856. //System.out.println("Track event: " + me);
  1857. // feed the 'dragged-over' event directly to the enter/exit
  1858. // code (not a real event so don't pass it to dispatchEvent)
  1859. Component targetOver = nativeContainer.getMouseEventTarget(me.getX(), me.getY(), true);
  1860. trackMouseEnterExit(targetOver, me);
  1861. }
  1862. /**
  1863. * Sends a mouse event to the current mouse event recipient using
  1864. * the given event (sent to the windowed host) as a srcEvent. If
  1865. * the mouse event target is still in the component tree, the
  1866. * coordinates of the event are translated to those of the target.
  1867. * If the target has been removed, we don't bother to send the
  1868. * message.
  1869. */
  1870. void retargetMouseEvent(Component target, int id, MouseEvent e) {
  1871. if (target == null) {
  1872. return; // mouse is over another hw component
  1873. }
  1874. int x = e.getX(), y = e.getY();
  1875. Component component;
  1876. for(component = target;
  1877. component != null && component != nativeContainer;
  1878. component = component.getParent()) {
  1879. x -= component.x;
  1880. y -= component.y;
  1881. }
  1882. if (component != null) {
  1883. MouseEvent retargeted = new MouseEvent(target,
  1884. id,
  1885. e.getWhen(),
  1886. e.getModifiers(),
  1887. x,
  1888. y,
  1889. e.getClickCount(),
  1890. e.isPopupTrigger());
  1891. ((AWTEvent)e).copyPrivateDataInto(retargeted);
  1892. if (target == nativeContainer) {
  1893. // avoid recursively calling LightweightDispatcher...
  1894. ((Container)target).dispatchEventToSelf(retargeted);
  1895. } else {
  1896. target.dispatchEvent(retargeted);
  1897. }
  1898. }
  1899. }
  1900. /**
  1901. * Set the cursor for a lightweight component
  1902. * Enforce that null cursor means inheriting from parent
  1903. */
  1904. void updateCursor(Component comp) {
  1905. // if user wants to change the cursor, we do it even mouse is dragging
  1906. // so LightweightDispatcher's dragging state is not checked here
  1907. if (comp != cursorOn) {
  1908. return;
  1909. }
  1910. if (comp == null) {
  1911. comp = nativeContainer;
  1912. }
  1913. Cursor cursor = comp.getIntrinsicCursor();
  1914. while (cursor == null && comp != nativeContainer) {
  1915. comp = comp.getParent();
  1916. if (comp == null) {
  1917. cursor = nativeContainer.getCursor();
  1918. break;
  1919. }
  1920. cursor = comp.getIntrinsicCursor();
  1921. }
  1922. if (cursor != lightCursor) {
  1923. lightCursor = cursor;
  1924. // Only change the cursor on the peer, because we want client code to think
  1925. // that the Container's cursor only changes in response to setCursor calls.
  1926. ComponentPeer ncPeer = nativeContainer.getPeer();
  1927. if (ncPeer != null) {
  1928. ncPeer.setCursor(cursor);
  1929. }
  1930. }
  1931. }
  1932. /**
  1933. * get the lightweight component mouse cursor is on
  1934. * null means the nativeContainer
  1935. */
  1936. Component getCursorOn() {
  1937. return cursorOn;
  1938. }
  1939. // --- member variables -------------------------------
  1940. /**
  1941. * The windowed container that might be hosting events for
  1942. * lightweight components.
  1943. */
  1944. private Container nativeContainer;
  1945. /**
  1946. * The current lightweight component that has focus that is being
  1947. * hosted by this container. If this is a null reference then
  1948. * there is currently no focus on a lightweight component being
  1949. * hosted by this container
  1950. */
  1951. private Component focus;
  1952. /**
  1953. * The current lightweight component being hosted by this windowed
  1954. * component that has mouse events being forwarded to it. If this
  1955. * is null, there are currently no mouse events being forwarded to
  1956. * a lightweight component.
  1957. */
  1958. private transient Component mouseEventTarget;
  1959. /**
  1960. * lightweight component the cursor is on
  1961. */
  1962. private transient Component cursorOn;
  1963. /**
  1964. * The last component entered
  1965. */
  1966. private transient Component targetLastEntered;
  1967. /**
  1968. * Is the mouse over the native container
  1969. */
  1970. private transient boolean isMouseInNativeContainer = false;
  1971. /**
  1972. * Is the next click event orphaned because the component hid/moved
  1973. */
  1974. private transient boolean isClickOrphaned = false;
  1975. /**
  1976. * Indicates if the mouse pointer is currently being dragged...
  1977. * this is needed because we may receive exit events while dragging
  1978. * and need to keep the current mouse target in this case.
  1979. */
  1980. private boolean dragging;
  1981. /**
  1982. * The cursor that is currently displayed for the lightwieght
  1983. * components. Remember this cursor, so we do not need to
  1984. * change cursor on every mouse event.
  1985. */
  1986. private transient Cursor lightCursor;
  1987. /**
  1988. * This variable is not used, but kept for serialization compatibility
  1989. */
  1990. private Cursor nativeCursor;
  1991. /**
  1992. * The event mask for contained lightweight components. Lightweight
  1993. * components need a windowed container to host window-related
  1994. * events. This seperate mask indicates events that have been
  1995. * requested by contained lightweight components without effecting
  1996. * the mask of the windowed component itself.
  1997. */
  1998. private long eventMask;
  1999. /**
  2000. * The kind of events routed to lightweight components from windowed
  2001. * hosts.
  2002. */
  2003. private static final long PROXY_EVENT_MASK =
  2004. AWTEvent.FOCUS_EVENT_MASK |
  2005. AWTEvent.KEY_EVENT_MASK |
  2006. AWTEvent.MOUSE_EVENT_MASK |
  2007. AWTEvent.MOUSE_MOTION_EVENT_MASK;
  2008. private static final long MOUSE_MASK =
  2009. AWTEvent.MOUSE_EVENT_MASK | AWTEvent.MOUSE_MOTION_EVENT_MASK;
  2010. }