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