1. /*
  2. * @(#)SwingUtilities.java 1.134 04/06/15
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing;
  8. import com.sun.java.swing.SwingUtilities2;
  9. import sun.swing.UIAction;
  10. import java.applet.*;
  11. import java.awt.*;
  12. import java.awt.event.*;
  13. import java.util.Vector;
  14. import java.util.Hashtable;
  15. import java.lang.reflect.*;
  16. import javax.accessibility.*;
  17. import javax.swing.event.MenuDragMouseEvent;
  18. import javax.swing.plaf.UIResource;
  19. import javax.swing.text.View;
  20. import sun.awt.AppContext;
  21. /**
  22. * A collection of utility methods for Swing.
  23. *
  24. * @version 1.134 06/15/04
  25. * @author unknown
  26. */
  27. public class SwingUtilities implements SwingConstants
  28. {
  29. // These states are system-wide, rather than AppContext wide.
  30. private static boolean canAccessEventQueue = false;
  31. private static boolean eventQueueTested = false;
  32. /**
  33. * Return true if <code>a</code> contains <code>b</code>
  34. */
  35. public static final boolean isRectangleContainingRectangle(Rectangle a,Rectangle b) {
  36. if (b.x >= a.x && (b.x + b.width) <= (a.x + a.width) &&
  37. b.y >= a.y && (b.y + b.height) <= (a.y + a.height)) {
  38. return true;
  39. }
  40. return false;
  41. }
  42. /**
  43. * Return the rectangle (0,0,bounds.width,bounds.height) for the component <code>aComponent</code>
  44. */
  45. public static Rectangle getLocalBounds(Component aComponent) {
  46. Rectangle b = new Rectangle(aComponent.getBounds());
  47. b.x = b.y = 0;
  48. return b;
  49. }
  50. /**
  51. * Returns the first <code>Window </code> ancestor of <code>c</code>, or
  52. * null if <code>c</code> is not contained inside a <code>Window</code>.
  53. *
  54. * @param c <code>Component</code> to get <code>Window</code> ancestor
  55. * of.
  56. * @return the first <code>Window </code> ancestor of <code>c</code>, or
  57. * null if <code>c</code> is not contained inside a
  58. * <code>Window</code>.
  59. */
  60. public static Window getWindowAncestor(Component c) {
  61. for(Container p = c.getParent(); p != null; p = p.getParent()) {
  62. if (p instanceof Window) {
  63. return (Window)p;
  64. }
  65. }
  66. return null;
  67. }
  68. /**
  69. * Converts the location <code>x</code> <code>y</code> to the
  70. * parents coordinate system, returning the location.
  71. */
  72. static Point convertScreenLocationToParent(Container parent,int x, int y) {
  73. for (Container p = parent; p != null; p = p.getParent()) {
  74. if (p instanceof Window) {
  75. Point point = new Point(x, y);
  76. SwingUtilities.convertPointFromScreen(point, parent);
  77. return point;
  78. }
  79. }
  80. throw new Error("convertScreenLocationToParent: no window ancestor");
  81. }
  82. /**
  83. * Convert a <code>aPoint</code> in <code>source</code> coordinate system to
  84. * <code>destination</code> coordinate system.
  85. * If <code>source></code>is null,<code>aPoint</code> is assumed to be in <code>destination</code>'s
  86. * root component coordinate system.
  87. * If <code>destination</code>is null, <code>aPoint</code> will be converted to <code>source</code>'s
  88. * root component coordinate system.
  89. * If both <code>source</code> and <code>destination</code> are null, return <code>aPoint</code>
  90. * without any conversion.
  91. */
  92. public static Point convertPoint(Component source,Point aPoint,Component destination) {
  93. Point p;
  94. if(source == null && destination == null)
  95. return aPoint;
  96. if(source == null) {
  97. source = getWindowAncestor(destination);
  98. if(source == null)
  99. throw new Error("Source component not connected to component tree hierarchy");
  100. }
  101. p = new Point(aPoint);
  102. convertPointToScreen(p,source);
  103. if(destination == null) {
  104. destination = getWindowAncestor(source);
  105. if(destination == null)
  106. throw new Error("Destination component not connected to component tree hierarchy");
  107. }
  108. convertPointFromScreen(p,destination);
  109. return p;
  110. }
  111. /**
  112. * Convert the point <code>(x,y)</code> in <code>source</code> coordinate system to
  113. * <code>destination</code> coordinate system.
  114. * If <code>source></code>is null,<code>(x,y)</code> is assumed to be in <code>destination</code>'s
  115. * root component coordinate system.
  116. * If <code>destination</code>is null, <code>(x,y)</code> will be converted to <code>source</code>'s
  117. * root component coordinate system.
  118. * If both <code>source</code> and <code>destination</code> are null, return <code>(x,y)</code>
  119. * without any conversion.
  120. */
  121. public static Point convertPoint(Component source,int x, int y,Component destination) {
  122. Point point = new Point(x,y);
  123. return convertPoint(source,point,destination);
  124. }
  125. /**
  126. * Convert the rectangle <code>aRectangle</code> in <code>source</code> coordinate system to
  127. * <code>destination</code> coordinate system.
  128. * If <code>source></code>is null,<code>aRectangle</code> is assumed to be in <code>destination</code>'s
  129. * root component coordinate system.
  130. * If <code>destination</code>is null, <code>aRectangle</code> will be converted to <code>source</code>'s
  131. * root component coordinate system.
  132. * If both <code>source</code> and <code>destination</code> are null, return <code>aRectangle</code>
  133. * without any conversion.
  134. */
  135. public static Rectangle convertRectangle(Component source,Rectangle aRectangle,Component destination) {
  136. Point point = new Point(aRectangle.x,aRectangle.y);
  137. point = convertPoint(source,point,destination);
  138. return new Rectangle(point.x,point.y,aRectangle.width,aRectangle.height);
  139. }
  140. /**
  141. * Convenience method for searching above <code>comp</code> in the
  142. * component hierarchy and returns the first object of class <code>c</code> it
  143. * finds. Can return null, if a class <code>c</code> cannot be found.
  144. */
  145. public static Container getAncestorOfClass(Class<?> c, Component comp)
  146. {
  147. if(comp == null || c == null)
  148. return null;
  149. Container parent = comp.getParent();
  150. while(parent != null && !(c.isInstance(parent)))
  151. parent = parent.getParent();
  152. return parent;
  153. }
  154. /**
  155. * Convenience method for searching above <code>comp</code> in the
  156. * component hierarchy and returns the first object of <code>name</code> it
  157. * finds. Can return null, if <code>name</code> cannot be found.
  158. */
  159. public static Container getAncestorNamed(String name, Component comp) {
  160. if(comp == null || name == null)
  161. return null;
  162. Container parent = comp.getParent();
  163. while(parent != null && !(name.equals(parent.getName())))
  164. parent = parent.getParent();
  165. return parent;
  166. }
  167. /**
  168. * Returns the deepest visible descendent Component of <code>parent</code>
  169. * that contains the location <code>x</code>, <code>y</code>.
  170. * If <code>parent</code> does not contain the specified location,
  171. * then <code>null</code> is returned. If <code>parent</code> is not a
  172. * container, or none of <code>parent</code>'s visible descendents
  173. * contain the specified location, <code>parent</code> is returned.
  174. *
  175. * @param parent the root component to begin the search
  176. * @param x the x target location
  177. * @param y the y target location
  178. */
  179. public static Component getDeepestComponentAt(Component parent, int x, int y) {
  180. if (!parent.contains(x, y)) {
  181. return null;
  182. }
  183. if (parent instanceof Container) {
  184. Component components[] = ((Container)parent).getComponents();
  185. for (int i = 0 ; i < components.length ; i++) {
  186. Component comp = components[i];
  187. if (comp != null && comp.isVisible()) {
  188. Point loc = comp.getLocation();
  189. if (comp instanceof Container) {
  190. comp = getDeepestComponentAt(comp, x - loc.x, y - loc.y);
  191. } else {
  192. comp = comp.getComponentAt(x - loc.x, y - loc.y);
  193. }
  194. if (comp != null && comp.isVisible()) {
  195. return comp;
  196. }
  197. }
  198. }
  199. }
  200. return parent;
  201. }
  202. /**
  203. * Returns a MouseEvent similar to <code>sourceEvent</code> except that its x
  204. * and y members have been converted to <code>destination</code>'s coordinate
  205. * system. If <code>source</code> is null, <code>sourceEvent</code> x and y members
  206. * are assumed to be into <code>destination</code>'s root component coordinate system.
  207. * If <code>destination</code> is <code>null</code>, the
  208. * returned MouseEvent will be in <code>source</code>'s coordinate system.
  209. * <code>sourceEvent</code> will not be changed. A new event is returned.
  210. * the <code>source</code> field of the returned event will be set
  211. * to <code>destination</code> if destination is non null
  212. * use the translateMouseEvent() method to translate a mouse event from
  213. * one component to another without changing the source.
  214. */
  215. public static MouseEvent convertMouseEvent(Component source,
  216. MouseEvent sourceEvent,
  217. Component destination) {
  218. Point p = convertPoint(source,new Point(sourceEvent.getX(),
  219. sourceEvent.getY()),
  220. destination);
  221. Component newSource;
  222. if(destination != null)
  223. newSource = destination;
  224. else
  225. newSource = source;
  226. MouseEvent newEvent;
  227. if (sourceEvent instanceof MouseWheelEvent) {
  228. MouseWheelEvent sourceWheelEvent = (MouseWheelEvent)sourceEvent;
  229. newEvent = new MouseWheelEvent(newSource,
  230. sourceWheelEvent.getID(),
  231. sourceWheelEvent.getWhen(),
  232. sourceWheelEvent.getModifiers(),
  233. p.x,p.y,
  234. sourceWheelEvent.getClickCount(),
  235. sourceWheelEvent.isPopupTrigger(),
  236. sourceWheelEvent.getScrollType(),
  237. sourceWheelEvent.getScrollAmount(),
  238. sourceWheelEvent.getWheelRotation());
  239. }
  240. else if (sourceEvent instanceof MenuDragMouseEvent) {
  241. MenuDragMouseEvent sourceMenuDragEvent = (MenuDragMouseEvent)sourceEvent;
  242. newEvent = new MenuDragMouseEvent(newSource,
  243. sourceMenuDragEvent.getID(),
  244. sourceMenuDragEvent.getWhen(),
  245. sourceMenuDragEvent.getModifiers(),
  246. p.x,p.y,
  247. sourceMenuDragEvent.getClickCount(),
  248. sourceMenuDragEvent.isPopupTrigger(),
  249. sourceMenuDragEvent.getPath(),
  250. sourceMenuDragEvent.getMenuSelectionManager());
  251. }
  252. else {
  253. newEvent = new MouseEvent(newSource,
  254. sourceEvent.getID(),
  255. sourceEvent.getWhen(),
  256. sourceEvent.getModifiers(),
  257. p.x,p.y,
  258. sourceEvent.getClickCount(),
  259. sourceEvent.isPopupTrigger());
  260. }
  261. return newEvent;
  262. }
  263. /**
  264. * Convert a point from a component's coordinate system to
  265. * screen coordinates.
  266. *
  267. * @param p a Point object (converted to the new coordinate system)
  268. * @param c a Component object
  269. */
  270. public static void convertPointToScreen(Point p,Component c) {
  271. Rectangle b;
  272. int x,y;
  273. do {
  274. if(c instanceof JComponent) {
  275. x = ((JComponent)c).getX();
  276. y = ((JComponent)c).getY();
  277. } else if(c instanceof java.applet.Applet ||
  278. c instanceof java.awt.Window) {
  279. try {
  280. Point pp = c.getLocationOnScreen();
  281. x = pp.x;
  282. y = pp.y;
  283. } catch (IllegalComponentStateException icse) {
  284. x = c.getX();
  285. y = c.getY();
  286. }
  287. } else {
  288. x = c.getX();
  289. y = c.getY();
  290. }
  291. p.x += x;
  292. p.y += y;
  293. if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
  294. break;
  295. c = c.getParent();
  296. } while(c != null);
  297. }
  298. /**
  299. * Convert a point from a screen coordinates to a component's
  300. * coordinate system
  301. *
  302. * @param p a Point object (converted to the new coordinate system)
  303. * @param c a Component object
  304. */
  305. public static void convertPointFromScreen(Point p,Component c) {
  306. Rectangle b;
  307. int x,y;
  308. do {
  309. if(c instanceof JComponent) {
  310. x = ((JComponent)c).getX();
  311. y = ((JComponent)c).getY();
  312. } else if(c instanceof java.applet.Applet ||
  313. c instanceof java.awt.Window) {
  314. try {
  315. Point pp = c.getLocationOnScreen();
  316. x = pp.x;
  317. y = pp.y;
  318. } catch (IllegalComponentStateException icse) {
  319. x = c.getX();
  320. y = c.getY();
  321. }
  322. } else {
  323. x = c.getX();
  324. y = c.getY();
  325. }
  326. p.x -= x;
  327. p.y -= y;
  328. if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
  329. break;
  330. c = c.getParent();
  331. } while(c != null);
  332. }
  333. /**
  334. * Returns the first <code>Window </code> ancestor of <code>c</code>, or
  335. * null if <code>c</code> is not contained inside a <code>Window</code>.
  336. * <p>
  337. * Note: This method provides the same functionality as
  338. * <code>getWindowAncestor</code>.
  339. *
  340. * @param c <code>Component</code> to get <code>Window</code> ancestor
  341. * of.
  342. * @return the first <code>Window </code> ancestor of <code>c</code>, or
  343. * null if <code>c</code> is not contained inside a
  344. * <code>Window</code>.
  345. */
  346. public static Window windowForComponent(Component c) {
  347. return getWindowAncestor(c);
  348. }
  349. /**
  350. * Return <code>true</code> if a component <code>a</code> descends from a component <code>b</code>
  351. */
  352. public static boolean isDescendingFrom(Component a,Component b) {
  353. if(a == b)
  354. return true;
  355. for(Container p = a.getParent();p!=null;p=p.getParent())
  356. if(p == b)
  357. return true;
  358. return false;
  359. }
  360. /**
  361. * Convenience to calculate the intersection of two rectangles
  362. * without allocating a new rectangle.
  363. * If the two rectangles don't intersect,
  364. * then the returned rectangle begins at (0,0)
  365. * and has zero width and height.
  366. *
  367. * @param x the X coordinate of the first rectangle's top-left point
  368. * @param y the Y coordinate of the first rectangle's top-left point
  369. * @param width the width of the first rectangle
  370. * @param height the height of the first rectangle
  371. * @param dest the second rectangle
  372. *
  373. * @return <code>dest</code>, modified to specify the intersection
  374. */
  375. public static Rectangle computeIntersection(int x,int y,int width,int height,Rectangle dest) {
  376. int x1 = (x > dest.x) ? x : dest.x;
  377. int x2 = ((x+width) < (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
  378. int y1 = (y > dest.y) ? y : dest.y;
  379. int y2 = ((y + height) < (dest.y + dest.height) ? (y+height) : (dest.y + dest.height));
  380. dest.x = x1;
  381. dest.y = y1;
  382. dest.width = x2 - x1;
  383. dest.height = y2 - y1;
  384. // If rectangles don't intersect, return zero'd intersection.
  385. if (dest.width < 0 || dest.height < 0) {
  386. dest.x = dest.y = dest.width = dest.height = 0;
  387. }
  388. return dest;
  389. }
  390. /**
  391. * Convenience method that calculates the union of two rectangles
  392. * without allocating a new rectangle.
  393. *
  394. * @param x the x-coordinate of the first rectangle
  395. * @param y the y-coordinate of the first rectangle
  396. * @param width the width of the first rectangle
  397. * @param height the height of the first rectangle
  398. * @param dest the coordinates of the second rectangle; the union
  399. * of the two rectangles is returned in this rectangle
  400. * @return the <code>dest</code> <code>Rectangle</code>
  401. */
  402. public static Rectangle computeUnion(int x,int y,int width,int height,Rectangle dest) {
  403. int x1 = (x < dest.x) ? x : dest.x;
  404. int x2 = ((x+width) > (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
  405. int y1 = (y < dest.y) ? y : dest.y;
  406. int y2 = ((y+height) > (dest.y + dest.height)) ? (y+height) : (dest.y + dest.height);
  407. dest.x = x1;
  408. dest.y = y1;
  409. dest.width = (x2 - x1);
  410. dest.height= (y2 - y1);
  411. return dest;
  412. }
  413. /**
  414. * Convenience returning an array of rect representing the regions within
  415. * <code>rectA</code> that do not overlap with <code>rectB</code>. If the
  416. * two Rects do not overlap, returns an empty array
  417. */
  418. public static Rectangle[] computeDifference(Rectangle rectA,Rectangle rectB) {
  419. if (rectB == null || !rectA.intersects(rectB) || isRectangleContainingRectangle(rectB,rectA)) {
  420. return new Rectangle[0];
  421. }
  422. Rectangle t = new Rectangle();
  423. Rectangle a=null,b=null,c=null,d=null;
  424. Rectangle result[];
  425. int rectCount = 0;
  426. /* rectA contains rectB */
  427. if (isRectangleContainingRectangle(rectA,rectB)) {
  428. t.x = rectA.x; t.y = rectA.y; t.width = rectB.x - rectA.x; t.height = rectA.height;
  429. if(t.width > 0 && t.height > 0) {
  430. a = new Rectangle(t);
  431. rectCount++;
  432. }
  433. t.x = rectB.x; t.y = rectA.y; t.width = rectB.width; t.height = rectB.y - rectA.y;
  434. if(t.width > 0 && t.height > 0) {
  435. b = new Rectangle(t);
  436. rectCount++;
  437. }
  438. t.x = rectB.x; t.y = rectB.y + rectB.height; t.width = rectB.width;
  439. t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
  440. if(t.width > 0 && t.height > 0) {
  441. c = new Rectangle(t);
  442. rectCount++;
  443. }
  444. t.x = rectB.x + rectB.width; t.y = rectA.y; t.width = rectA.x + rectA.width - (rectB.x + rectB.width);
  445. t.height = rectA.height;
  446. if(t.width > 0 && t.height > 0) {
  447. d = new Rectangle(t);
  448. rectCount++;
  449. }
  450. } else {
  451. /* 1 */
  452. if (rectB.x <= rectA.x && rectB.y <= rectA.y) {
  453. if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
  454. t.x = rectA.x; t.y = rectB.y + rectB.height;
  455. t.width = rectA.width; t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
  456. if(t.width > 0 && t.height > 0) {
  457. a = t;
  458. rectCount++;
  459. }
  460. } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  461. t.setBounds((rectB.x + rectB.width), rectA.y,
  462. (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  463. if(t.width > 0 && t.height > 0) {
  464. a = t;
  465. rectCount++;
  466. }
  467. } else {
  468. t.setBounds((rectB.x + rectB.width), rectA.y,
  469. (rectA.x + rectA.width) - (rectB.x + rectB.width),
  470. (rectB.y + rectB.height) - rectA.y);
  471. if(t.width > 0 && t.height > 0) {
  472. a = new Rectangle(t);
  473. rectCount++;
  474. }
  475. t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  476. (rectA.y + rectA.height) - (rectB.y + rectB.height));
  477. if(t.width > 0 && t.height > 0) {
  478. b = new Rectangle(t);
  479. rectCount++;
  480. }
  481. }
  482. } else if (rectB.x <= rectA.x && (rectB.y + rectB.height) >= (rectA.y + rectA.height)) {
  483. if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
  484. t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  485. if(t.width > 0 && t.height > 0) {
  486. a = t;
  487. rectCount++;
  488. }
  489. } else {
  490. t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  491. if(t.width > 0 && t.height > 0) {
  492. a = new Rectangle(t);
  493. rectCount++;
  494. }
  495. t.setBounds((rectB.x + rectB.width), rectB.y,
  496. (rectA.x + rectA.width) - (rectB.x + rectB.width),
  497. (rectA.y + rectA.height) - rectB.y);
  498. if(t.width > 0 && t.height > 0) {
  499. b = new Rectangle(t);
  500. rectCount++;
  501. }
  502. }
  503. } else if (rectB.x <= rectA.x) {
  504. if ((rectB.x + rectB.width) >= (rectA.x + rectA.width)) {
  505. t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  506. if(t.width>0 && t.height > 0) {
  507. a = new Rectangle(t);
  508. rectCount++;
  509. }
  510. t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  511. (rectA.y + rectA.height) - (rectB.y + rectB.height));
  512. if(t.width > 0 && t.height > 0) {
  513. b = new Rectangle(t);
  514. rectCount++;
  515. }
  516. } else {
  517. t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  518. if(t.width > 0 && t.height > 0) {
  519. a = new Rectangle(t);
  520. rectCount++;
  521. }
  522. t.setBounds((rectB.x + rectB.width), rectB.y,
  523. (rectA.x + rectA.width) - (rectB.x + rectB.width),
  524. rectB.height);
  525. if(t.width > 0 && t.height > 0) {
  526. b = new Rectangle(t);
  527. rectCount++;
  528. }
  529. t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  530. (rectA.y + rectA.height) - (rectB.y + rectB.height));
  531. if(t.width > 0 && t.height > 0) {
  532. c = new Rectangle(t);
  533. rectCount++;
  534. }
  535. }
  536. } else if (rectB.x <= (rectA.x + rectA.width) && (rectB.x + rectB.width) > (rectA.x + rectA.width)) {
  537. if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  538. t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  539. if(t.width > 0 && t.height > 0) {
  540. a = t;
  541. rectCount++;
  542. }
  543. } else if (rectB.y <= rectA.y) {
  544. t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x,
  545. (rectB.y + rectB.height) - rectA.y);
  546. if(t.width > 0 && t.height > 0) {
  547. a = new Rectangle(t);
  548. rectCount++;
  549. }
  550. t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  551. (rectA.y + rectA.height) - (rectB.y + rectB.height));
  552. if(t.width > 0 && t.height > 0) {
  553. b = new Rectangle(t);
  554. rectCount++;
  555. }
  556. } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  557. t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  558. if(t.width > 0 && t.height > 0) {
  559. a = new Rectangle(t);
  560. rectCount++;
  561. }
  562. t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
  563. (rectA.y + rectA.height) - rectB.y);
  564. if(t.width > 0 && t.height > 0) {
  565. b = new Rectangle(t);
  566. rectCount++;
  567. }
  568. } else {
  569. t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  570. if(t.width > 0 && t.height > 0) {
  571. a = new Rectangle(t);
  572. rectCount++;
  573. }
  574. t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
  575. rectB.height);
  576. if(t.width > 0 && t.height > 0) {
  577. b = new Rectangle(t);
  578. rectCount++;
  579. }
  580. t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  581. (rectA.y + rectA.height) - (rectB.y + rectB.height));
  582. if(t.width > 0 && t.height > 0) {
  583. c = new Rectangle(t);
  584. rectCount++;
  585. }
  586. }
  587. } else if (rectB.x >= rectA.x && (rectB.x + rectB.width) <= (rectA.x + rectA.width)) {
  588. if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  589. t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  590. if(t.width > 0 && t.height > 0) {
  591. a = new Rectangle(t);
  592. rectCount++;
  593. }
  594. t.setBounds((rectB.x + rectB.width), rectA.y,
  595. (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  596. if(t.width > 0 && t.height > 0) {
  597. b = new Rectangle(t);
  598. rectCount++;
  599. }
  600. } else if (rectB.y <= rectA.y) {
  601. t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  602. if(t.width > 0 && t.height > 0) {
  603. a = new Rectangle(t);
  604. rectCount++;
  605. }
  606. t.setBounds(rectB.x, (rectB.y + rectB.height),
  607. rectB.width,
  608. (rectA.y + rectA.height) - (rectB.y + rectB.height));
  609. if(t.width > 0 && t.height > 0) {
  610. b = new Rectangle(t);
  611. rectCount++;
  612. }
  613. t.setBounds((rectB.x + rectB.width), rectA.y,
  614. (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  615. if(t.width > 0 && t.height > 0) {
  616. c = new Rectangle(t);
  617. rectCount++;
  618. }
  619. } else {
  620. t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  621. if(t.width > 0 && t.height > 0) {
  622. a = new Rectangle(t);
  623. rectCount++;
  624. }
  625. t.setBounds(rectB.x, rectA.y, rectB.width,
  626. rectB.y - rectA.y);
  627. if(t.width > 0 && t.height > 0) {
  628. b = new Rectangle(t);
  629. rectCount++;
  630. }
  631. t.setBounds((rectB.x + rectB.width), rectA.y,
  632. (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  633. if(t.width > 0 && t.height > 0) {
  634. c = new Rectangle(t);
  635. rectCount++;
  636. }
  637. }
  638. }
  639. }
  640. result = new Rectangle[rectCount];
  641. rectCount = 0;
  642. if(a != null)
  643. result[rectCount++] = a;
  644. if(b != null)
  645. result[rectCount++] = b;
  646. if(c != null)
  647. result[rectCount++] = c;
  648. if(d != null)
  649. result[rectCount++] = d;
  650. return result;
  651. }
  652. /**
  653. * Returns true if the mouse event specifies the left mouse button.
  654. *
  655. * @param anEvent a MouseEvent object
  656. * @return true if the left mouse button was active
  657. */
  658. public static boolean isLeftMouseButton(MouseEvent anEvent) {
  659. return ((anEvent.getModifiers() & InputEvent.BUTTON1_MASK) != 0);
  660. }
  661. /**
  662. * Returns true if the mouse event specifies the middle mouse button.
  663. *
  664. * @param anEvent a MouseEvent object
  665. * @return true if the middle mouse button was active
  666. */
  667. public static boolean isMiddleMouseButton(MouseEvent anEvent) {
  668. return ((anEvent.getModifiers() & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASK);
  669. }
  670. /**
  671. * Returns true if the mouse event specifies the right mouse button.
  672. *
  673. * @param anEvent a MouseEvent object
  674. * @return true if the right mouse button was active
  675. */
  676. public static boolean isRightMouseButton(MouseEvent anEvent) {
  677. return ((anEvent.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK);
  678. }
  679. /**
  680. * Compute the width of the string using a font with the specified
  681. * "metrics" (sizes).
  682. *
  683. * @param fm a FontMetrics object to compute with
  684. * @param str the String to compute
  685. * @return an int containing the string width
  686. */
  687. public static int computeStringWidth(FontMetrics fm,String str) {
  688. // You can't assume that a string's width is the sum of its
  689. // characters' widths in Java2D -- it may be smaller due to
  690. // kerning, etc.
  691. return SwingUtilities2.stringWidth(null, fm, str);
  692. }
  693. /**
  694. * Compute and return the location of the icons origin, the
  695. * location of origin of the text baseline, and a possibly clipped
  696. * version of the compound labels string. Locations are computed
  697. * relative to the viewR rectangle.
  698. * The JComponents orientation (LEADING/TRAILING) will also be taken
  699. * into account and translated into LEFT/RIGHT values accordingly.
  700. */
  701. public static String layoutCompoundLabel(JComponent c,
  702. FontMetrics fm,
  703. String text,
  704. Icon icon,
  705. int verticalAlignment,
  706. int horizontalAlignment,
  707. int verticalTextPosition,
  708. int horizontalTextPosition,
  709. Rectangle viewR,
  710. Rectangle iconR,
  711. Rectangle textR,
  712. int textIconGap)
  713. {
  714. boolean orientationIsLeftToRight = true;
  715. int hAlign = horizontalAlignment;
  716. int hTextPos = horizontalTextPosition;
  717. if (c != null) {
  718. if (!(c.getComponentOrientation().isLeftToRight())) {
  719. orientationIsLeftToRight = false;
  720. }
  721. }
  722. // Translate LEADING/TRAILING values in horizontalAlignment
  723. // to LEFT/RIGHT values depending on the components orientation
  724. switch (horizontalAlignment) {
  725. case LEADING:
  726. hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
  727. break;
  728. case TRAILING:
  729. hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
  730. break;
  731. }
  732. // Translate LEADING/TRAILING values in horizontalTextPosition
  733. // to LEFT/RIGHT values depending on the components orientation
  734. switch (horizontalTextPosition) {
  735. case LEADING:
  736. hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
  737. break;
  738. case TRAILING:
  739. hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
  740. break;
  741. }
  742. return layoutCompoundLabelImpl(c,
  743. fm,
  744. text,
  745. icon,
  746. verticalAlignment,
  747. hAlign,
  748. verticalTextPosition,
  749. hTextPos,
  750. viewR,
  751. iconR,
  752. textR,
  753. textIconGap);
  754. }
  755. /**
  756. * Compute and return the location of the icons origin, the
  757. * location of origin of the text baseline, and a possibly clipped
  758. * version of the compound labels string. Locations are computed
  759. * relative to the viewR rectangle.
  760. * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
  761. * values in horizontalTextPosition (they will default to RIGHT) and in
  762. * horizontalAlignment (they will default to CENTER).
  763. * Use the other version of layoutCompoundLabel() instead.
  764. */
  765. public static String layoutCompoundLabel(
  766. FontMetrics fm,
  767. String text,
  768. Icon icon,
  769. int verticalAlignment,
  770. int horizontalAlignment,
  771. int verticalTextPosition,
  772. int horizontalTextPosition,
  773. Rectangle viewR,
  774. Rectangle iconR,
  775. Rectangle textR,
  776. int textIconGap)
  777. {
  778. return layoutCompoundLabelImpl(null, fm, text, icon,
  779. verticalAlignment,
  780. horizontalAlignment,
  781. verticalTextPosition,
  782. horizontalTextPosition,
  783. viewR, iconR, textR, textIconGap);
  784. }
  785. /**
  786. * Compute and return the location of the icons origin, the
  787. * location of origin of the text baseline, and a possibly clipped
  788. * version of the compound labels string. Locations are computed
  789. * relative to the viewR rectangle.
  790. * This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
  791. * values in horizontalTextPosition (they will default to RIGHT) and in
  792. * horizontalAlignment (they will default to CENTER).
  793. * Use the other version of layoutCompoundLabel() instead.
  794. */
  795. private static String layoutCompoundLabelImpl(
  796. JComponent c,
  797. FontMetrics fm,
  798. String text,
  799. Icon icon,
  800. int verticalAlignment,
  801. int horizontalAlignment,
  802. int verticalTextPosition,
  803. int horizontalTextPosition,
  804. Rectangle viewR,
  805. Rectangle iconR,
  806. Rectangle textR,
  807. int textIconGap)
  808. {
  809. /* Initialize the icon bounds rectangle iconR.
  810. */
  811. if (icon != null) {
  812. iconR.width = icon.getIconWidth();
  813. iconR.height = icon.getIconHeight();
  814. }
  815. else {
  816. iconR.width = iconR.height = 0;
  817. }
  818. /* Initialize the text bounds rectangle textR. If a null
  819. * or and empty String was specified we substitute "" here
  820. * and use 0,0,0,0 for textR.
  821. */
  822. boolean textIsEmpty = (text == null) || text.equals("");
  823. int lsb = 0;
  824. /* Unless both text and icon are non-null, we effectively ignore
  825. * the value of textIconGap.
  826. */
  827. int gap;
  828. View v = null;
  829. if (textIsEmpty) {
  830. textR.width = textR.height = 0;
  831. text = "";
  832. gap = 0;
  833. }
  834. else {
  835. int availTextWidth;
  836. gap = (icon == null) ? 0 : textIconGap;
  837. if (horizontalTextPosition == CENTER) {
  838. availTextWidth = viewR.width;
  839. }
  840. else {
  841. availTextWidth = viewR.width - (iconR.width + gap);
  842. }
  843. v = (c != null) ? (View) c.getClientProperty("html") : null;
  844. if (v != null) {
  845. textR.width = Math.min(availTextWidth,
  846. (int) v.getPreferredSpan(View.X_AXIS));
  847. textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
  848. } else {
  849. textR.width = SwingUtilities2.stringWidth(c, fm, text);
  850. lsb = SwingUtilities2.getLeftSideBearing(c, fm, text);
  851. if (lsb < 0) {
  852. // If lsb is negative, add it to the width and later
  853. // adjust the x location. This gives more space than is
  854. // actually needed.
  855. // This is done like this for two reasons:
  856. // 1. If we set the width to the actual bounds all
  857. // callers would have to account for negative lsb
  858. // (pref size calculations ONLY look at width of
  859. // textR)
  860. // 2. You can do a drawString at the returned location
  861. // and the text won't be clipped.
  862. textR.width -= lsb;
  863. }
  864. if (textR.width > availTextWidth) {
  865. text = SwingUtilities2.clipString(c, fm, text,
  866. availTextWidth);
  867. textR.width = SwingUtilities2.stringWidth(c, fm, text);
  868. }
  869. textR.height = fm.getHeight();
  870. }
  871. }
  872. /* Compute textR.x,y given the verticalTextPosition and
  873. * horizontalTextPosition properties
  874. */
  875. if (verticalTextPosition == TOP) {
  876. if (horizontalTextPosition != CENTER) {
  877. textR.y = 0;
  878. }
  879. else {
  880. textR.y = -(textR.height + gap);
  881. }
  882. }
  883. else if (verticalTextPosition == CENTER) {
  884. textR.y = (iconR.height / 2) - (textR.height / 2);
  885. }
  886. else { // (verticalTextPosition == BOTTOM)
  887. if (horizontalTextPosition != CENTER) {
  888. textR.y = iconR.height - textR.height;
  889. }
  890. else {
  891. textR.y = (iconR.height + gap);
  892. }
  893. }
  894. if (horizontalTextPosition == LEFT) {
  895. textR.x = -(textR.width + gap);
  896. }
  897. else if (horizontalTextPosition == CENTER) {
  898. textR.x = (iconR.width / 2) - (textR.width / 2);
  899. }
  900. else { // (horizontalTextPosition == RIGHT)
  901. textR.x = (iconR.width + gap);
  902. }
  903. /* labelR is the rectangle that contains iconR and textR.
  904. * Move it to its proper position given the labelAlignment
  905. * properties.
  906. *
  907. * To avoid actually allocating a Rectangle, Rectangle.union
  908. * has been inlined below.
  909. */
  910. int labelR_x = Math.min(iconR.x, textR.x);
  911. int labelR_width = Math.max(iconR.x + iconR.width,
  912. textR.x + textR.width) - labelR_x;
  913. int labelR_y = Math.min(iconR.y, textR.y);
  914. int labelR_height = Math.max(iconR.y + iconR.height,
  915. textR.y + textR.height) - labelR_y;
  916. int dx, dy;
  917. if (verticalAlignment == TOP) {
  918. dy = viewR.y - labelR_y;
  919. }
  920. else if (verticalAlignment == CENTER) {
  921. dy = (viewR.y + (viewR.height / 2)) - (labelR_y + (labelR_height / 2));
  922. }
  923. else { // (verticalAlignment == BOTTOM)
  924. dy = (viewR.y + viewR.height) - (labelR_y + labelR_height);
  925. }
  926. if (horizontalAlignment == LEFT) {
  927. dx = viewR.x - labelR_x;
  928. }
  929. else if (horizontalAlignment == RIGHT) {
  930. dx = (viewR.x + viewR.width) - (labelR_x + labelR_width);
  931. }
  932. else { // (horizontalAlignment == CENTER)
  933. dx = (viewR.x + (viewR.width / 2)) -
  934. (labelR_x + (labelR_width / 2));
  935. }
  936. /* Translate textR and glypyR by dx,dy.
  937. */
  938. textR.x += dx;
  939. textR.y += dy;
  940. iconR.x += dx;
  941. iconR.y += dy;
  942. if (lsb < 0) {
  943. // lsb is negative. Shift the x location so that the text is
  944. // visually drawn at the right location.
  945. textR.x -= lsb;
  946. }
  947. return text;
  948. }
  949. /**
  950. * Paints a component <code>c</code> on an arbitrary graphics
  951. * <code>g</code> in the
  952. * specified rectangle, specifying the rectangle's upper left corner
  953. * and size. The component is reparented to a private
  954. * container (whose parent becomes p) which prevents
  955. * <code>c.validate()</code> and <code>c.repaint()</code>
  956. * calls from propagating up the tree. The intermediate
  957. * container has no other effect.
  958. *
  959. * <p>
  960. * The component should either descend from <code>JComponent</code>
  961. * or be another kind of lightweight component.
  962. * A lightweight component is one whose "lightweight" property
  963. * (returned by the <code>Component</code>
  964. * <code>isLightweight</code> method)
  965. * is true. If the Component is not lightweight, bad things map happen:
  966. * crashes, exceptions, painting problems...
  967. * <p>
  968. *
  969. * @param g the <code>Graphics</code> object to draw on
  970. * @param c the <code>Component</code> to draw
  971. * @param p the intermediate <code>Container</code>
  972. * @param x an int specifying the left side of the area draw in, in pixels,
  973. * measured from the left edge of the graphics context
  974. * @param y an int specifying the top of the area to draw in, in pixels
  975. * measured down from the top edge of the graphics context
  976. * @param w an int specifying the width of the area draw in, in pixels
  977. * @param h an int specifying the height of the area draw in, in pixels
  978. *
  979. * @see java.awt.Component#isLightweight
  980. */
  981. public static void paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h) {
  982. getCellRendererPane(c, p).paintComponent(g, c, p, x, y, w, h,false);
  983. }
  984. /**
  985. * Paints a component <code>c</code> on an arbitrary graphics
  986. * <code>g</code> in the specified rectangle, specifying a Rectangle object.
  987. * The component is reparented to a private
  988. * container (whose parent becomes <code>p</code>) which prevents
  989. * <code>c.validate()</code> and <code>c.repaint()</code>
  990. * calls from propagating up the tree. The intermediate
  991. * container has no other effect.
  992. *
  993. * <p>
  994. * The component should either descend from <code>JComponent</code>
  995. * or be another kind of lightweight component.
  996. * A lightweight component is one whose "lightweight" property
  997. * (returned by the <code>Component</code>
  998. * <code>isLightweight</code> method)
  999. * is true. If the Component is not lightweight, bad things map happen:
  1000. * crashes, exceptions, painting problems...
  1001. * <p>
  1002. *
  1003. * @param g the <code>Graphics</code> object to draw on
  1004. * @param c the <code>Component</code> to draw
  1005. * @param p the intermediate <code>Container</code>
  1006. * @param r the <code>Rectangle</code> to draw in
  1007. *
  1008. * @see java.awt.Component#isLightweight
  1009. */
  1010. public static void paintComponent(Graphics g, Component c, Container p, Rectangle r) {
  1011. paintComponent(g, c, p, r.x, r.y, r.width, r.height);
  1012. }
  1013. /*
  1014. * Ensures that cell renderer <code>c</code> has a
  1015. * <code>ComponentShell</code> parent and that
  1016. * the shell's parent is p.
  1017. */
  1018. private static CellRendererPane getCellRendererPane(Component c, Container p) {
  1019. Container shell = c.getParent();
  1020. if (shell instanceof CellRendererPane) {
  1021. if (shell.getParent() != p) {
  1022. p.add(shell);
  1023. }
  1024. } else {
  1025. shell = new CellRendererPane();
  1026. shell.add(c);
  1027. p.add(shell);
  1028. }
  1029. return (CellRendererPane)shell;
  1030. }
  1031. /**
  1032. * A simple minded look and feel change: ask each node in the tree
  1033. * to <code>updateUI()</code> -- that is, to initialize its UI property
  1034. * with the current look and feel.
  1035. */
  1036. public static void updateComponentTreeUI(Component c) {
  1037. updateComponentTreeUI0(c);
  1038. c.invalidate();
  1039. c.validate();
  1040. c.repaint();
  1041. }
  1042. private static void updateComponentTreeUI0(Component c) {
  1043. if (c instanceof JComponent) {
  1044. ((JComponent) c).updateUI();
  1045. }
  1046. Component[] children = null;
  1047. if (c instanceof JMenu) {
  1048. children = ((JMenu)c).getMenuComponents();
  1049. }
  1050. else if (c instanceof Container) {
  1051. children = ((Container)c).getComponents();
  1052. }
  1053. if (children != null) {
  1054. for(int i = 0; i < children.length; i++) {
  1055. updateComponentTreeUI0(children[i]);
  1056. }
  1057. }
  1058. }
  1059. /**
  1060. * Causes <i>doRun.run()</i> to be executed asynchronously on the
  1061. * AWT event dispatching thread. This will happen after all
  1062. * pending AWT events have been processed. This method should
  1063. * be used when an application thread needs to update the GUI.
  1064. * In the following example the <code>invokeLater</code> call queues
  1065. * the <code>Runnable</code> object <code>doHelloWorld</code>
  1066. * on the event dispatching thread and
  1067. * then prints a message.
  1068. * <pre>
  1069. * Runnable doHelloWorld = new Runnable() {
  1070. * public void run() {
  1071. * System.out.println("Hello World on " + Thread.currentThread());
  1072. * }
  1073. * };
  1074. *
  1075. * SwingUtilities.invokeLater(doHelloWorld);
  1076. * System.out.println("This might well be displayed before the other message.");
  1077. * </pre>
  1078. * If invokeLater is called from the event dispatching thread --
  1079. * for example, from a JButton's ActionListener -- the <i>doRun.run()</i> will
  1080. * still be deferred until all pending events have been processed.
  1081. * Note that if the <i>doRun.run()</i> throws an uncaught exception
  1082. * the event dispatching thread will unwind (not the current thread).
  1083. * <p>
  1084. * Additional documentation and examples for this method can be
  1085. * found in
  1086. * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How to Use Threads</a>,
  1087. * in <em>The Java Tutorial</em>.
  1088. * <p>
  1089. * As of 1.3 this method is just a cover for <code>java.awt.EventQueue.invokeLater()</code>.
  1090. *
  1091. * @see #invokeAndWait
  1092. */
  1093. public static void invokeLater(Runnable doRun) {
  1094. EventQueue.invokeLater(doRun);
  1095. }
  1096. /**
  1097. * Causes <code>doRun.run()</code> to be executed synchronously on the
  1098. * AWT event dispatching thread. This call blocks until
  1099. * all pending AWT events have been processed and (then)
  1100. * <code>doRun.run()</code> returns. This method should
  1101. * be used when an application thread needs to update the GUI.
  1102. * It should'nt be called from the <code>EventDispatchThread</code>.
  1103. * Here's an example that creates a new application thread
  1104. * that uses <code>invokeAndWait</code> to print a string from the event
  1105. * dispatching thread and then, when that's finished, print
  1106. * a string from the application thread.
  1107. * <pre>
  1108. * final Runnable doHelloWorld = new Runnable() {
  1109. * public void run() {
  1110. * System.out.println("Hello World on " + Thread.currentThread());
  1111. * }
  1112. * };
  1113. *
  1114. * Thread appThread = new Thread() {
  1115. * public void run() {
  1116. * try {
  1117. * SwingUtilities.invokeAndWait(doHelloWorld);
  1118. * }
  1119. * catch (Exception e) {
  1120. * e.printStackTrace();
  1121. * }
  1122. * System.out.println("Finished on " + Thread.currentThread());
  1123. * }
  1124. * };
  1125. * appThread.start();
  1126. * </pre>
  1127. * Note that if the <code>Runnable.run</code> method throws an
  1128. * uncaught exception
  1129. * (on the event dispatching thread) it's caught and rethrown, as
  1130. * an <code>InvocationTargetException</code>, on the caller's thread.
  1131. * <p>
  1132. * Additional documentation and examples for this method can be
  1133. * found in
  1134. * <A HREF="http://java.sun.com/docs/books/tutorial/uiswing/misc/threads.html">How to Use Threads</a>,
  1135. * in <em>The Java Tutorial</em>.
  1136. * <p>
  1137. * As of 1.3 this method is just a cover for
  1138. * <code>java.awt.EventQueue.invokeAndWait()</code>.
  1139. *
  1140. * @exception InterruptedException if we're interrupted while waiting for
  1141. * the event dispatching thread to finish excecuting
  1142. * <code>doRun.run()</code>
  1143. * @exception InvocationTargetException if an exception is thrown
  1144. * while running <code>doRun</code>
  1145. *
  1146. * @see #invokeLater
  1147. */
  1148. public static void invokeAndWait(final Runnable doRun)
  1149. throws InterruptedException, InvocationTargetException
  1150. {
  1151. EventQueue.invokeAndWait(doRun);
  1152. }
  1153. /**
  1154. * Returns true if the current thread is an AWT event dispatching thread.
  1155. * <p>
  1156. * As of 1.3 this method is just a cover for
  1157. * <code>java.awt.EventQueue.isDispatchThread()</code>.
  1158. *
  1159. * @return true if the current thread is an AWT event dispatching thread
  1160. */
  1161. public static boolean isEventDispatchThread()
  1162. {
  1163. return EventQueue.isDispatchThread();
  1164. }
  1165. /*
  1166. * --- Accessibility Support ---
  1167. *
  1168. */
  1169. /**
  1170. * Get the index of this object in its accessible parent.<p>
  1171. *
  1172. * Note: as of the Java 2 platform v1.3, it is recommended that developers call
  1173. * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
  1174. * of using this method.
  1175. *
  1176. * @return -1 of this object does not have an accessible parent.
  1177. * Otherwise, the index of the child in its accessible parent.
  1178. */
  1179. public static int getAccessibleIndexInParent(Component c) {
  1180. return c.getAccessibleContext().getAccessibleIndexInParent();
  1181. }
  1182. /**
  1183. * Returns the <code>Accessible</code> child contained at the
  1184. * local coordinate <code>Point</code>, if one exists.
  1185. * Otherwise returns <code>null</code>.
  1186. *
  1187. * @return the <code>Accessible</code> at the specified location,
  1188. * if it exists; otherwise <code>null</code>
  1189. */
  1190. public static Accessible getAccessibleAt(Component c, Point p) {
  1191. if (c instanceof Container) {
  1192. return c.getAccessibleContext().getAccessibleComponent().getAccessibleAt(p);
  1193. } else if (c instanceof Accessible) {
  1194. Accessible a = (Accessible) c;
  1195. if (a != null) {
  1196. AccessibleContext ac = a.getAccessibleContext();
  1197. if (ac != null) {
  1198. AccessibleComponent acmp;
  1199. Point location;
  1200. int nchildren = ac.getAccessibleChildrenCount();
  1201. for (int i=0; i < nchildren; i++) {
  1202. a = ac.getAccessibleChild(i);
  1203. if ((a != null)) {
  1204. ac = a.getAccessibleContext();
  1205. if (ac != null) {
  1206. acmp = ac.getAccessibleComponent();
  1207. if ((acmp != null) && (acmp.isShowing())) {
  1208. location = acmp.getLocation();
  1209. Point np = new Point(p.x-location.x,
  1210. p.y-location.y);
  1211. if (acmp.contains(np)){
  1212. return a;
  1213. }
  1214. }
  1215. }
  1216. }
  1217. }
  1218. }
  1219. }
  1220. return (Accessible) c;
  1221. }
  1222. return null;
  1223. }
  1224. /**
  1225. * Get the state of this object. <p>
  1226. *
  1227. * Note: as of the Java 2 platform v1.3, it is recommended that developers call
  1228. * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
  1229. * of using this method.
  1230. *
  1231. * @return an instance of AccessibleStateSet containing the current state
  1232. * set of the object
  1233. * @see AccessibleState
  1234. */
  1235. public static AccessibleStateSet getAccessibleStateSet(Component c) {
  1236. return c.getAccessibleContext().getAccessibleStateSet();
  1237. }
  1238. /**
  1239. * Returns the number of accessible children in the object. If all
  1240. * of the children of this object implement Accessible, than this
  1241. * method should return the number of children of this object. <p>
  1242. *
  1243. * Note: as of the Java 2 platform v1.3, it is recommended that developers call
  1244. * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
  1245. * of using this method.
  1246. *
  1247. * @return the number of accessible children in the object.
  1248. */
  1249. public static int getAccessibleChildrenCount(Component c) {
  1250. return c.getAccessibleContext().getAccessibleChildrenCount();
  1251. }
  1252. /**
  1253. * Return the nth Accessible child of the object. <p>
  1254. *
  1255. * Note: as of the Java 2 platform v1.3, it is recommended that developers call
  1256. * Component.AccessibleAWTComponent.getAccessibleIndexInParent() instead
  1257. * of using this method.
  1258. *
  1259. * @param i zero-based index of child
  1260. * @return the nth Accessible child of the object
  1261. */
  1262. public static Accessible getAccessibleChild(Component c, int i) {
  1263. return c.getAccessibleContext().getAccessibleChild(i);
  1264. }
  1265. /**
  1266. * Return the child <code>Component</code> of the specified
  1267. * <code>Component</code> that is the focus owner, if any.
  1268. *
  1269. * @param c the root of the <code>Component</code> hierarchy to
  1270. * search for the focus owner
  1271. * @return the focus owner, or <code>null</code> if there is no focus
  1272. * owner, or if the focus owner is not <code>comp</code>, or a
  1273. * descendant of <code>comp</code>
  1274. *
  1275. * @see java.awt.KeyboardFocusManager#getFocusOwner
  1276. * @deprecated As of 1.4, replaced by
  1277. * <code>KeyboardFocusManager.getFocusOwner()</code>.
  1278. */
  1279. @Deprecated
  1280. public static Component findFocusOwner(Component c) {
  1281. Component focusOwner = KeyboardFocusManager.
  1282. getCurrentKeyboardFocusManager().getFocusOwner();
  1283. // verify focusOwner is a descendant of c
  1284. for (Component temp = focusOwner; temp != null;
  1285. temp = (temp instanceof Window) ? null : temp.getParent())
  1286. {
  1287. if (temp == c) {
  1288. return focusOwner;
  1289. }
  1290. }
  1291. return null;
  1292. }
  1293. /**
  1294. * If c is a JRootPane descendant return its JRootPane ancestor.
  1295. * If c is a RootPaneContainer then return its JRootPane.
  1296. * @return the JRootPane for Component c or null.
  1297. */
  1298. public static JRootPane getRootPane(Component c) {
  1299. if (c instanceof RootPaneContainer) {
  1300. return ((RootPaneContainer)c).getRootPane();
  1301. }
  1302. for( ; c != null; c = c.getParent()) {
  1303. if (c instanceof JRootPane) {
  1304. return (JRootPane)c;
  1305. }
  1306. }
  1307. return null;
  1308. }
  1309. /**
  1310. * Returns the root component for the current component tree.
  1311. * @return the first ancestor of c that's a Window or the last Applet ancestor
  1312. */
  1313. public static Component getRoot(Component c) {
  1314. Component applet = null;
  1315. for(Component p = c; p != null; p = p.getParent()) {
  1316. if (p instanceof Window) {
  1317. return p;
  1318. }
  1319. if (p instanceof Applet) {
  1320. applet = p;
  1321. }
  1322. }
  1323. return applet;
  1324. }
  1325. /**
  1326. * Process the key bindings for the <code>Component</code> associated with
  1327. * <code>event</code>. This method is only useful if
  1328. * <code>event.getComponent()</code> does not descend from
  1329. * <code>JComponent</code>, or your are not invoking
  1330. * <code>super.processKeyEvent</code> from within your
  1331. * <code>JComponent</code> subclass. <code>JComponent</code>
  1332. * automatically processes bindings from within its
  1333. * <code>processKeyEvent</code> method, hence you rarely need
  1334. * to directly invoke this method.
  1335. *
  1336. * @param event KeyEvent used to identify which bindings to process, as
  1337. * well as which Component has focus.
  1338. * @return true if a binding has found and processed
  1339. * @since 1.4
  1340. */
  1341. public static boolean processKeyBindings(KeyEvent event) {
  1342. if (event != null) {
  1343. if (event.isConsumed()) {
  1344. return false;
  1345. }
  1346. Component component = event.getComponent();
  1347. Component last = component;
  1348. boolean pressed = (event.getID() == KeyEvent.KEY_PRESSED);
  1349. if (!isValidKeyEventForKeyBindings(event)) {
  1350. return false;
  1351. }
  1352. // Find the first JComponent in the ancestor hierarchy, and
  1353. // invoke processKeyBindings on it
  1354. while (component != null) {
  1355. if (component instanceof JComponent) {
  1356. return ((JComponent)component).processKeyBindings(
  1357. event, pressed);
  1358. }
  1359. last = component;
  1360. component = component.getParent();
  1361. }
  1362. // No JComponents, if Window or Applet parent, process
  1363. // WHEN_IN_FOCUSED_WINDOW bindings.
  1364. if ((last instanceof Applet) || (last instanceof Window)) {
  1365. return JComponent.processKeyBindingsForAllComponents(
  1366. event, (Container)last, pressed);
  1367. }
  1368. }
  1369. return false;
  1370. }
  1371. /**
  1372. * Returns true if the <code>e</code> is a valid KeyEvent to use in
  1373. * processing the key bindings associated with JComponents.
  1374. */
  1375. static boolean isValidKeyEventForKeyBindings(KeyEvent e) {
  1376. if (e.getID() == KeyEvent.KEY_TYPED) {
  1377. int mod = e.getModifiers();
  1378. if (((mod & ActionEvent.ALT_MASK) != 0) &&
  1379. ((mod & ActionEvent.CTRL_MASK) == 0)) {
  1380. // filter out typed "alt-?" keys, but not those created
  1381. // with AltGr, and not control characters
  1382. return false;
  1383. }
  1384. }
  1385. return true;
  1386. }
  1387. /**
  1388. * Invokes <code>actionPerformed</code> on <code>action</code> if
  1389. * <code>action</code> is enabled (and non null). The command for the
  1390. * ActionEvent is determined by:
  1391. * <ol>
  1392. * <li>If the action was registered via
  1393. * <code>registerKeyboardAction</code>, then the command string
  1394. * passed in (null will be used if null was passed in).
  1395. * <li>Action value with name Action.ACTION_COMMAND_KEY, unless null.
  1396. * <li>String value of the KeyEvent, unless <code>getKeyChar</code>
  1397. * returns KeyEvent.CHAR_UNDEFINED..
  1398. * </ol>
  1399. * This will return true if <code>action</code> is non-null and
  1400. * actionPerformed is invoked on it.
  1401. *
  1402. * @since 1.3
  1403. */
  1404. public static boolean notifyAction(Action action, KeyStroke ks,
  1405. KeyEvent event, Object sender,
  1406. int modifiers) {
  1407. if (action == null) {
  1408. return false;
  1409. }
  1410. if (action instanceof UIAction) {
  1411. if (!((UIAction)action).isEnabled(sender)) {
  1412. return false;
  1413. }
  1414. }
  1415. else if (!action.isEnabled()) {
  1416. return false;
  1417. }
  1418. Object commandO;
  1419. boolean stayNull;
  1420. // Get the command object.
  1421. commandO = action.getValue(Action.ACTION_COMMAND_KEY);
  1422. if (commandO == null && (action instanceof JComponent.ActionStandin)) {
  1423. // ActionStandin is used for historical reasons to support
  1424. // registerKeyboardAction with a null value.
  1425. stayNull = true;
  1426. }
  1427. else {
  1428. stayNull = false;
  1429. }
  1430. // Convert it to a string.
  1431. String command;
  1432. if (commandO != null) {
  1433. command = commandO.toString();
  1434. }
  1435. else if (!stayNull && event.getKeyChar() != KeyEvent.CHAR_UNDEFINED) {
  1436. command = String.valueOf(event.getKeyChar());
  1437. }
  1438. else {
  1439. // Do null for undefined chars, or if registerKeyboardAction
  1440. // was called with a null.
  1441. command = null;
  1442. }
  1443. action.actionPerformed(new ActionEvent(sender,
  1444. ActionEvent.ACTION_PERFORMED, command, event.getWhen(),
  1445. modifiers));
  1446. return true;
  1447. }
  1448. /**
  1449. * Convenience method to change the UI InputMap for <code>component</code>
  1450. * to <code>uiInputMap</code>. If <code>uiInputMap</code> is null,
  1451. * this removes any previously installed UI InputMap.
  1452. *
  1453. * @since 1.3
  1454. */
  1455. public static void replaceUIInputMap(JComponent component, int type,
  1456. InputMap uiInputMap) {
  1457. InputMap map = component.getInputMap(type, (uiInputMap != null));
  1458. while (map != null) {
  1459. InputMap parent = map.getParent();
  1460. if (parent == null || (parent instanceof UIResource)) {
  1461. map.setParent(uiInputMap);
  1462. return;
  1463. }
  1464. map = parent;
  1465. }
  1466. }
  1467. /**
  1468. * Convenience method to change the UI ActionMap for <code>component</code>
  1469. * to <code>uiActionMap</code>. If <code>uiActionMap</code> is null,
  1470. * this removes any previously installed UI ActionMap.
  1471. *
  1472. * @since 1.3
  1473. */
  1474. public static void replaceUIActionMap(JComponent component,
  1475. ActionMap uiActionMap) {
  1476. ActionMap map = component.getActionMap((uiActionMap != null));;
  1477. while (map != null) {
  1478. ActionMap parent = map.getParent();
  1479. if (parent == null || (parent instanceof UIResource)) {
  1480. map.setParent(uiActionMap);
  1481. return;
  1482. }
  1483. map = parent;
  1484. }
  1485. }
  1486. /**
  1487. * Returns the InputMap provided by the UI for condition
  1488. * <code>condition</code> in component <code>component</code>.
  1489. * <p>This will return null if the UI has not installed a InputMap
  1490. * of the specified type.
  1491. *
  1492. * @since 1.3
  1493. */
  1494. public static InputMap getUIInputMap(JComponent component, int condition) {
  1495. InputMap map = component.getInputMap(condition, false);
  1496. while (map != null) {
  1497. InputMap parent = map.getParent();
  1498. if (parent instanceof UIResource) {
  1499. return parent;
  1500. }
  1501. map = parent;
  1502. }
  1503. return null;
  1504. }
  1505. /**
  1506. * Returns the ActionMap provided by the UI
  1507. * in component <code>component</code>.
  1508. * <p>This will return null if the UI has not installed an ActionMap.
  1509. *
  1510. * @since 1.3
  1511. */
  1512. public static ActionMap getUIActionMap(JComponent component) {
  1513. ActionMap map = component.getActionMap(false);
  1514. while (map != null) {
  1515. ActionMap parent = map.getParent();
  1516. if (parent instanceof UIResource) {
  1517. return parent;
  1518. }
  1519. map = parent;
  1520. }
  1521. return null;
  1522. }
  1523. // Don't use String, as it's not guaranteed to be unique in a Hashtable.
  1524. private static final Object sharedOwnerFrameKey =
  1525. new StringBuffer("SwingUtilities.sharedOwnerFrame");
  1526. static class SharedOwnerFrame extends Frame implements WindowListener {
  1527. public void addNotify() {
  1528. super.addNotify();
  1529. installListeners();
  1530. }
  1531. /**
  1532. * Install window listeners on owned windows to watch for displayability changes
  1533. */
  1534. void installListeners() {
  1535. Window[] windows = getOwnedWindows();
  1536. for (int ind = 0; ind < windows.length; ind++){
  1537. Window window = windows[ind];
  1538. if (window != null) {
  1539. window.removeWindowListener(this);
  1540. window.addWindowListener(this);
  1541. }
  1542. }
  1543. }
  1544. /**
  1545. * Watches for displayability changes and disposes shared instance if there are no
  1546. * displayable children left.
  1547. */
  1548. public void windowClosed(WindowEvent e) {
  1549. synchronized(getTreeLock()) {
  1550. Window[] windows = getOwnedWindows();
  1551. for (int ind = 0; ind < windows.length; ind++) {
  1552. Window window = windows[ind];
  1553. if (window != null) {
  1554. if (window.isDisplayable()) {
  1555. return;
  1556. }
  1557. window.removeWindowListener(this);
  1558. }
  1559. }
  1560. dispose();
  1561. }
  1562. }
  1563. public void windowOpened(WindowEvent e) {
  1564. }
  1565. public void windowClosing(WindowEvent e) {
  1566. }
  1567. public void windowIconified(WindowEvent e) {
  1568. }
  1569. public void windowDeiconified(WindowEvent e) {
  1570. }
  1571. public void windowActivated(WindowEvent e) {
  1572. }
  1573. public void windowDeactivated(WindowEvent e) {
  1574. }
  1575. public void show() {
  1576. // This frame can never be shown
  1577. }
  1578. public void dispose() {
  1579. try {
  1580. getToolkit().getSystemEventQueue();
  1581. super.dispose();
  1582. } catch (Exception e) {
  1583. // untrusted code not allowed to dispose
  1584. }
  1585. }
  1586. }
  1587. /**
  1588. * Returns a toolkit-private, shared, invisible Frame
  1589. * to be the owner for JDialogs and JWindows created with
  1590. * null owners.
  1591. * @exception HeadlessException if GraphicsEnvironment.isHeadless()
  1592. * returns true.
  1593. * @see java.awt.GraphicsEnvironment#isHeadless
  1594. */
  1595. static Frame getSharedOwnerFrame() throws HeadlessException {
  1596. Frame sharedOwnerFrame =
  1597. (Frame)SwingUtilities.appContextGet(sharedOwnerFrameKey);
  1598. if (sharedOwnerFrame == null) {
  1599. sharedOwnerFrame = new SharedOwnerFrame();
  1600. SwingUtilities.appContextPut(sharedOwnerFrameKey,
  1601. sharedOwnerFrame);
  1602. }
  1603. return sharedOwnerFrame;
  1604. }
  1605. /**
  1606. * Returns a SharedOwnerFrame's shutdown listener to dispose the SharedOwnerFrame
  1607. * if it has no more displayable children.
  1608. * @exception HeadlessException if GraphicsEnvironment.isHeadless()
  1609. * returns true.
  1610. * @see java.awt.GraphicsEnvironment#isHeadless
  1611. */
  1612. static WindowListener getSharedOwnerFrameShutdownListener() throws HeadlessException {
  1613. Frame sharedOwnerFrame = getSharedOwnerFrame();
  1614. return (WindowListener)sharedOwnerFrame;
  1615. }
  1616. /* Don't make these AppContext accessors public or protected --
  1617. * since AppContext is in sun.awt in 1.2, we shouldn't expose it
  1618. * even indirectly with a public API.
  1619. */
  1620. // REMIND(aim): phase out use of 4 methods below since they
  1621. // are just private covers for AWT methods (?)
  1622. static Object appContextGet(Object key) {
  1623. return AppContext.getAppContext().get(key);
  1624. }
  1625. static void appContextPut(Object key, Object value) {
  1626. AppContext.getAppContext().put(key, value);
  1627. }
  1628. static void appContextRemove(Object key) {
  1629. AppContext.getAppContext().remove(key);
  1630. }
  1631. static Class loadSystemClass(String className) throws ClassNotFoundException {
  1632. return Class.forName(className, true, Thread.currentThread().
  1633. getContextClassLoader());
  1634. }
  1635. /*
  1636. * Convenience function for determining ComponentOrientation. Helps us
  1637. * avoid having Munge directives throughout the code.
  1638. */
  1639. static boolean isLeftToRight( Component c ) {
  1640. return c.getComponentOrientation().isLeftToRight();
  1641. }
  1642. private SwingUtilities() {
  1643. throw new Error("SwingUtilities is just a container for static methods");
  1644. }
  1645. /**
  1646. * Returns true if the Icon <code>icon</code> is an instance of
  1647. * ImageIcon, and the image it contains is the same as <code>image</code>.
  1648. */
  1649. static boolean doesIconReferenceImage(Icon icon, Image image) {
  1650. Image iconImage = (icon != null && (icon instanceof ImageIcon)) ?
  1651. ((ImageIcon)icon).getImage() : null;
  1652. return (iconImage == image);
  1653. }
  1654. /**
  1655. * Returns index of the first occurrence of <code>mnemonic</code>
  1656. * within string <code>text</code>. Matching algorithm is not
  1657. * case-sensitive.
  1658. *
  1659. * @param text The text to search through, may be null
  1660. * @param mnemonic The mnemonic to find the character for.
  1661. * @return index into the string if exists, otherwise -1
  1662. */
  1663. static int findDisplayedMnemonicIndex(String text, int mnemonic) {
  1664. if (text == null || mnemonic == '\0') {
  1665. return -1;
  1666. }
  1667. char uc = Character.toUpperCase((char)mnemonic);
  1668. char lc = Character.toLowerCase((char)mnemonic);
  1669. int uci = text.indexOf(uc);
  1670. int lci = text.indexOf(lc);
  1671. if (uci == -1) {
  1672. return lci;
  1673. } else if(lci == -1) {
  1674. return uci;
  1675. } else {
  1676. return (lci < uci) ? lci : uci;
  1677. }
  1678. }
  1679. /**
  1680. * Stores the position and size of
  1681. * the inner painting area of the specified component
  1682. * in <code>r</code> and returns <code>r</code>.
  1683. * The position and size specify the bounds of the component,
  1684. * adjusted so as not to include the border area (the insets).
  1685. * This method is useful for classes
  1686. * that implement painting code.
  1687. *
  1688. * @param c the JComponent in question; if null, this method returns null
  1689. * @param r the Rectangle instance to be modified;
  1690. * may be null
  1691. * @return null if the Component is null;
  1692. * otherwise, returns the passed-in rectangle (if non-null)
  1693. * or a new rectangle specifying position and size information
  1694. *
  1695. * @since 1.4
  1696. */
  1697. public static Rectangle calculateInnerArea(JComponent c, Rectangle r) {
  1698. if (c == null) {
  1699. return null;
  1700. }
  1701. Rectangle rect = r;
  1702. Insets insets = c.getInsets();
  1703. if (rect == null) {
  1704. rect = new Rectangle();
  1705. }
  1706. rect.x = insets.left;
  1707. rect.y = insets.top;
  1708. rect.width = c.getWidth() - insets.left - insets.right;
  1709. rect.height = c.getHeight() - insets.top - insets.bottom;
  1710. return rect;
  1711. }
  1712. }