home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / swing / SwingUtilities.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  46.2 KB  |  1,344 lines

  1. /*
  2.  * @(#)SwingUtilities.java    1.47 98/02/04
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20. package java.awt.swing;
  21.  
  22. import java.awt.*;
  23. import java.util.Vector;
  24. import java.awt.event.*;
  25. import java.lang.reflect.*;
  26.  
  27. import java.awt.accessibility.*;
  28.  
  29. /**
  30.  * A collection of conveniences for Swing
  31.  *
  32.  * @version 1.47 02/04/98
  33.  * @author Arnaud Weber
  34.  */
  35. // PENDING(klobad) Really need a dispatchEventImpl() method for glass to be useful.
  36. public class SwingUtilities implements SwingConstants {
  37.  
  38.     // These states are system-wide, rather than AppContext wide.
  39.     private static boolean canAccessEventQueue = false;
  40.     private static boolean eventQueueTested = false;
  41.  
  42.  
  43.     /** Return true if <code>a</code> contains <code>b</code> **/
  44.     public static final boolean isRectangleContainingRectangle(Rectangle a,Rectangle b) {
  45.         if (b.x >= a.x && (b.x + b.width) <= (a.x + a.width) &&
  46.             b.y >= a.y && (b.y + b.height) <= (a.y + a.height)) {
  47.             return true;
  48.         }
  49.         return false;
  50.     }
  51.  
  52.     /** Return the rectangle (0,0,bounds.width,bounds.height) for the component <code>aComponent</code>
  53.      */
  54.     public static Rectangle getLocalBounds(Component aComponent) {
  55.     Rectangle b = new Rectangle(aComponent.getBounds());
  56.     b.x = b.y = 0;
  57.     return b;
  58.     }
  59.  
  60.     private static java.awt.Window getWindowAncestor(Component c) {
  61.         Container parent;
  62.         for(parent = c.getParent() ; c != null ; parent = parent.getParent()) {
  63.             if(parent instanceof java.awt.Window)
  64.                 return (java.awt.Window) parent;
  65.         }
  66.         return null;
  67.     }
  68.  
  69.     /** Convert a <b>aPoint</b> in <b>source</b> coordinate system to
  70.      *  <b>destination</b> coordinate system.
  71.      *  If <b>source></b>is null,<b>aPoint</b> is assumed to be in <b>destination</b>'s
  72.      *  root component coordinate system.
  73.      *  If <b>destination</b>is null, <b>aPoint</b> will be converted to <b>source</b>'s
  74.      *  root component coordinate system.
  75.      *  If both <b>source</b> and <b>destination</b> are null, return <b>aPoint</b>
  76.      *  without any conversion.
  77.      */
  78.     public static Point convertPoint(Component source,Point aPoint,Component destination) {
  79.         Point p;
  80.  
  81.         if(source == null && destination == null)
  82.             return aPoint;
  83.         if(source == null) {
  84.             source = getWindowAncestor(destination);
  85.             if(source == null)
  86.                 throw new Error("Source component not connected to component tree hierarchy");
  87.         }
  88.         p = new Point(aPoint);
  89.         convertPointToScreen(p,source);
  90.         if(destination == null) {
  91.             destination = getWindowAncestor(source);
  92.             if(destination == null)
  93.                 throw new Error("Destination component not connected to component tree hierarchy");
  94.         }
  95.         convertPointFromScreen(p,destination);
  96.         return p;
  97.     }
  98.  
  99.     /** Convert the point <b>(x,y)</b> in <b>source</b> coordinate system to
  100.      *  <b>destination</b> coordinate system.
  101.      *  If <b>source></b>is null,<b>(x,y)</b> is assumed to be in <b>destination</b>'s
  102.      *  root component coordinate system.
  103.      *  If <b>destination</b>is null, <b>(x,y)</b> will be converted to <b>source</b>'s
  104.      *  root component coordinate system.
  105.      *  If both <b>source</b> and <b>destination</b> are null, return <b>(x,y)</b>
  106.      *  without any conversion.
  107.      */
  108.     public static Point convertPoint(Component source,int x, int y,Component destination) {
  109.         Point point = new Point(x,y);
  110.         return convertPoint(source,point,destination);
  111.     }
  112.  
  113.     /** Convert the rectangle <b>aRectangle</b> in <b>source</b> coordinate system to
  114.      *  <b>destination</b> coordinate system.
  115.      *  If <b>source></b>is null,<b>aRectangle</b> is assumed to be in <b>destination</b>'s
  116.      *  root component coordinate system.
  117.      *  If <b>destination</b>is null, <b>aRectangle</b> will be converted to <b>source</b>'s
  118.      *  root component coordinate system.
  119.      *  If both <b>source</b> and <b>destination</b> are null, return <b>aRectangle</b>
  120.      *  without any conversion.
  121.      */
  122.     public static Rectangle convertRectangle(Component source,Rectangle aRectangle,Component destination) {
  123.         Point point = new Point(aRectangle.x,aRectangle.y);
  124.         point =  convertPoint(source,point,destination);
  125.     return new Rectangle(point.x,point.y,aRectangle.width,aRectangle.height);
  126.     }
  127.  
  128.     /** Convience method for searching above <b>comp</b> in the 
  129.       * component hierarchy and returns the first object of class <b>c</b> it
  130.       * finds. Can return null, if a class <b>c</b> cannot be found.
  131.       */
  132.     public static Container getAncestorOfClass(Class c, Component comp) {
  133.     if(comp == null || c == null) 
  134.         return null;
  135.     
  136.     Container parent = comp.getParent();
  137.     while(parent != null && !(c.isInstance(parent)))
  138.         parent = parent.getParent();
  139.     return parent;
  140.     }
  141.  
  142.     /** Convience method for searching above <b>comp</b> in the 
  143.       * component hierarchy and returns the first object of <b>name</b> it
  144.       * finds. Can return null, if <b>name</b> cannot be found.
  145.       */
  146.     public static Container getAncestorNamed(String name, Component comp) {
  147.     if(comp == null || name == null) 
  148.         return null;
  149.     
  150.     Container parent = comp.getParent();
  151.     while(parent != null && !(name.equals(parent.getName())))
  152.         parent = parent.getParent();
  153.     return parent;
  154.     }
  155.  
  156.     /**
  157.       * Returns the deepest child Component of parent that is at the location
  158.       * <b>x</b>, <b>y</b>. If <b>parent</b> is not a Container, it is
  159.       * returned, otherwise this method is messaged again with the child
  160.       * component at <b>x</b>, <b>y</b>.
  161.       */
  162.     public static Component getDeepestComponentAt(Component parent, int x,
  163.                           int y) {
  164.     if(parent != null && parent instanceof Container) {
  165.         Component child = ((Container)parent).getComponentAt(x, y);
  166.  
  167.         if(child != null && child != parent && child.isVisible()) {
  168.                 Rectangle b = child.getBounds();
  169.         child = getDeepestComponentAt(child, x - b.x,y-b.y);
  170.         if(child != null)
  171.             return child;
  172.         }
  173.     }
  174.     return parent;
  175.     }
  176.  
  177.     /** Returns a MouseEvent similar to <b>sourceEvent</b> except that its x
  178.      * and y members have been converted to <B>destination</B>'s coordinate
  179.      * system.  If <b>source</b> is null, <b>sourceEvent</b> x and y members
  180.      * are assumed to be into <b>destination<b>'s root component coordinate system.
  181.      * If <B>destination</B> is <b>null</b>, the
  182.      * returned MouseEvent will be in <b>source</b>'s coordinate system.
  183.      * <b>sourceEvent</b> will not be changed. A new event is returned.
  184.      * the <b>source<b> field of the returned event will be set
  185.      * to <b>destination</b> if destination is non null
  186.      * use translateMouseEvent() to translate a mouse event from one component
  187.      * to another without changing the source.
  188.      */
  189.     public static MouseEvent convertMouseEvent(Component source,
  190.                                                MouseEvent sourceEvent,
  191.                                                Component destination) {
  192.     Point p = convertPoint(source,new Point(sourceEvent.getX(),
  193.                                                 sourceEvent.getY()),
  194.                                destination);
  195.     Component newSource;
  196.  
  197.     if(destination != null)
  198.         newSource = destination;
  199.     else
  200.         newSource = source;
  201.  
  202.     return new MouseEvent(newSource,
  203.                   sourceEvent.getID(),
  204.                   sourceEvent.getWhen(),
  205.                   sourceEvent.getModifiers(),
  206.                   p.x,p.y,
  207.                   sourceEvent.getClickCount(),
  208.                   sourceEvent.isPopupTrigger());
  209.     }
  210.  
  211.  
  212.     public static void convertPointToScreen(Point p,Component c) {
  213.             Rectangle b;
  214.             int x,y;
  215.  
  216.             do { 
  217.                 if(c instanceof JComponent) {
  218.                     x = ((JComponent)c).getX();
  219.                     y = ((JComponent)c).getY();
  220.                 } else if(c instanceof java.applet.Applet) {
  221.                     Point pp = c.getLocationOnScreen();
  222.                     x = pp.x;
  223.                     y = pp.y;
  224.                 } else {
  225.                     b = c.getBounds();
  226.                     x = b.x;
  227.                     y = b.y;
  228.                 }
  229.  
  230.                 p.x += x;
  231.                 p.y += y;
  232.  
  233.                 if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
  234.                     break;
  235.                 c = c.getParent();
  236.             } while(c != null);
  237.         }
  238.  
  239.     public static void convertPointFromScreen(Point p,Component c) {
  240.         Rectangle b;
  241.         int x,y;
  242.  
  243.         do {
  244.             if(c instanceof JComponent) {
  245.                 x = ((JComponent)c).getX();
  246.                 y = ((JComponent)c).getY();
  247.             }  else if(c instanceof java.applet.Applet) {
  248.                 Point pp = c.getLocationOnScreen();
  249.                 x = pp.x;
  250.                 y = pp.y;
  251.             } else {
  252.                 b = c.getBounds();
  253.                 x = b.x;
  254.                 y = b.y;
  255.             }
  256.  
  257.             p.x -= x;
  258.             p.y -= y;
  259.  
  260.             if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
  261.                 break;
  262.             c = c.getParent();
  263.         } while(c != null);
  264.     }
  265.  
  266.     /** Return <code>aComponent</code>'s window **/
  267.     public static Window windowForComponent(Component aComponent) {
  268.         for (Container p = aComponent.getParent(); p != null; p = p.getParent()) {
  269.             if (p instanceof Window) {
  270.         return (Window)p;
  271.         }
  272.     }
  273.         return null;
  274.     }
  275.  
  276.     /** Return <code>true</code> if a component <code>a</code> descends from a component <code>b</code>
  277.      */
  278.     public static boolean isDescendingFrom(Component a,Component b) {
  279.         if(a == b)
  280.             return true;
  281.         for(Container p = a.getParent();p!=null;p=p.getParent())
  282.             if(p == b)
  283.                 return true;
  284.         return false;
  285.     }
  286.  
  287.     static synchronized EventQueue getEventQueue() {
  288.       if(!eventQueueTested) {
  289.     EventQueue eq;
  290.     
  291.     try {
  292.       eq= Toolkit.getDefaultToolkit().getSystemEventQueue();
  293.       canAccessEventQueue = true;
  294.     } catch(Exception e) {
  295.       canAccessEventQueue = false;
  296.     }
  297.     eventQueueTested = true;
  298.       }
  299.       if(eventQueueTested) {
  300.     if(canAccessEventQueue)
  301.       return Toolkit.getDefaultToolkit().getSystemEventQueue();
  302.       } 
  303.       return null;
  304.     }
  305.  
  306.     /**
  307.      * Causes <i>obj</i> to have its run() method called in the dispatch
  308.      * thread of the EventQueue.  This will happen after all pending events
  309.      * are processed.
  310.      */
  311.     public static void invokeLater(Runnable obj) {
  312.       EventQueue queue =  getEventQueue();
  313.       if(queue != null) {
  314.         InvokeComponent component = new InvokeComponent(obj);
  315.         InvokeEvent event = new InvokeEvent(component);
  316.     queue.postEvent(event);
  317.       }    else {
  318.     new TimerInvoker(obj);
  319.       }
  320.     }
  321.  
  322.     // This variable is system-wide, rather than AppContext-wide.
  323.     private static Class eventDispatchThreadClass = null;
  324.  
  325.  
  326.     /** 
  327.      * @return true if the current thread is the event dispatching thread.
  328.      */
  329.     public static boolean isEventDispatchThread() 
  330.     {
  331.     Thread currentThread = Thread.currentThread();
  332.  
  333.     /* The first time we're called on what appears to be the event
  334.      * dispatching thread, we stash the threads class in 
  335.      * eventDispatchThreadClass.  Subsequently we effectively
  336.      * return eventDispatchThreadClass instanceof Thread.currentThread().
  337.      */
  338.  
  339.     if (eventDispatchThreadClass == null) {
  340.         Class currentThreadClass = currentThread.getClass();
  341.  
  342.         /* This test is a crock.  It's known to work on all of the popular
  343.          * JDK1.1 implementations available as of January 1998. 
  344.          */
  345.         if((currentThreadClass.getName().indexOf("EventDispatchThread") >= 0) || 
  346.            (currentThreadClass.getName().indexOf("JMEventQueue") >= 0)) {
  347.         eventDispatchThreadClass = currentThreadClass;
  348.         return true;
  349.         }
  350.         else {
  351.         return false;
  352.         }
  353.     }
  354.     
  355.     return eventDispatchThreadClass.isInstance(currentThread);
  356.     }
  357.  
  358.  
  359.     /**
  360.      * Causes <i>obj</i> to have its run() method called in the dispatch
  361.      * thread of the EventQueue.  This will happen after all pending events
  362.      * are processed.  The call blocks until this has happened.  This method
  363.      * will throw and error if called from the event dispatcher thread.
  364.      *
  365.      * @exception  InterruptedException  if another thread has
  366.      *             interrupted this thread.
  367.      * @exception  InvocationTargetException  if an exception is thrown when
  368.      *             running <i>obj</i>.
  369.      */
  370.     public static void invokeAndWait(Runnable obj) throws InterruptedException, InvocationTargetException {
  371.       EventQueue queue =  getEventQueue();
  372.  
  373.       if(isEventDispatchThread ()) {
  374.           throw new Error("Cannot call invokeAndWait from the event dispatcher thread");
  375.       }
  376.       if(queue != null) {
  377.         InvokeComponent component = new InvokeComponent(obj);
  378.         InvokeEvent event = new InvokeEvent(component);
  379.     synchronized (component.lock) {
  380.       queue.postEvent(event);
  381.       component.lock.wait();
  382.     }
  383.     if (component.exception != null) {
  384.       throw new InvocationTargetException(component.exception);
  385.     }
  386.       } else {
  387.     TimerInvoker ti = new TimerInvoker(obj,false);
  388.     synchronized(ti.lock) {
  389.       ti.start();
  390.       ti.lock.wait();
  391.     }
  392.       }
  393.     }
  394.  
  395.     static class InvokeComponent extends Component {
  396.         static final int EventID = 10000;
  397.  
  398.         Runnable runnable;
  399.         Object lock;
  400.         Exception exception;
  401.  
  402.         InvokeComponent(Runnable runnable) {
  403.             super();
  404.             enableEvents(EventID);
  405.             this.runnable = runnable;
  406.             lock = new Object();
  407.         }
  408.  
  409.         protected void processEvent(AWTEvent event) {
  410.             try {
  411.                 runnable.run();
  412.             } catch (Exception e) {
  413.                 exception = e;
  414.             }
  415.             synchronized (lock) {
  416.                 lock.notifyAll();
  417.             }
  418.         }
  419.     }
  420.  
  421.     static class InvokeEvent extends AWTEvent {
  422.         InvokeEvent(Component c) {
  423.             super(c, InvokeComponent.EventID);
  424.         }
  425.     }
  426.     /*
  427.      * Convenience to calculate an intersection of two rectangles without allocating a new rectangle
  428.      * Return dest.
  429.      */
  430.     public static Rectangle computeIntersection(int x,int y,int width,int height,Rectangle dest) {
  431.         int x1 = (x > dest.x) ? x : dest.x;
  432.     int x2 = ((x+width) < (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
  433.     int y1 = (y > dest.y) ? y : dest.y;
  434.     int y2 = ((y + height) < (dest.y + dest.height) ? (y+height) : (dest.y + dest.height));
  435.         
  436.         dest.x = x1;
  437.         dest.y = y1;
  438.         dest.width = x2 - x1;
  439.         dest.height = y2 - y1;
  440.         return dest;
  441.     }
  442.  
  443.     /*
  444.      * Convenience to calculate the union of two rectangles without allocating a new rectangle
  445.      * Return dest
  446.      */
  447.     public static Rectangle computeUnion(int x,int y,int width,int height,Rectangle dest) {
  448.         int x1 = (x < dest.x) ? x : dest.x;
  449.     int x2 = ((x+width) > (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
  450.     int y1 = (y < dest.y) ? y : dest.y;
  451.     int y2 = ((y+height) > (dest.y + dest.height)) ? (y+height) : (dest.y + dest.height);
  452.         
  453.         dest.x = x1;
  454.         dest.y = y1;
  455.         dest.width = (x2 - x1);
  456.         dest.height= (y2 - y1);
  457.         return dest;
  458.     }
  459.  
  460.     /*
  461.      * Convenience returning an array of rect representing the regions within 
  462.      * <code>rectA</code> that do not overlap with <code>rectB</code>. If the
  463.      * two Rects do not overlap, return an empty array
  464.      */
  465.     public static Rectangle[] computeDifference(Rectangle rectA,Rectangle rectB) {
  466.         if (rectB == null || !rectA.intersects(rectB) || isRectangleContainingRectangle(rectB,rectA)) {
  467.             return new Rectangle[0];
  468.         }
  469.  
  470.         Rectangle t = new Rectangle();
  471.         Rectangle a=null,b=null,c=null,d=null;
  472.         Rectangle result[];
  473.         int rectCount = 0;
  474.  
  475.         /* rectA contains rectB */
  476.         if (isRectangleContainingRectangle(rectA,rectB)) {
  477.             t.x = rectA.x; t.y = rectA.y; t.width = rectB.x - rectA.x; t.height = rectA.height;
  478.             if(t.width > 0 && t.height > 0) {
  479.                 a = new Rectangle(t);
  480.                 rectCount++;
  481.             }
  482.  
  483.             t.x = rectB.x; t.y = rectA.y; t.width = rectB.width; t.height = rectB.y - rectA.y;
  484.             if(t.width > 0 && t.height > 0) {
  485.                 b = new Rectangle(t);
  486.                 rectCount++;
  487.             }
  488.  
  489.             t.x = rectB.x; t.y = rectB.y + rectB.height; t.width = rectB.width; 
  490.             t.height = rectA.y + rectA.height - rectB.y + rectB.height;
  491.             if(t.width > 0 && t.height > 0) {
  492.                 c = new Rectangle(t);
  493.                 rectCount++;
  494.             }
  495.  
  496.             t.x = rectB.x + rectB.width; t.y = rectA.y; t.width = rectA.x + rectA.width - rectB.x + rectB.width;
  497.             t.height = rectA.height;
  498.             if(t.width > 0 && t.height > 0) {
  499.                 d = new Rectangle(t);
  500.                 rectCount++;
  501.             }
  502.         } else {
  503.             /* 1 */
  504.             if (rectB.x <= rectA.x && rectB.y <= rectA.y) {
  505.                 if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
  506.                     t.x = rectA.x; t.y = rectB.y + rectB.height;
  507.                     t.width = rectA.width; t.height = rectA.y + rectA.height - rectB.y + rectB.height;
  508.                     if(t.width > 0 && t.height > 0) {
  509.                         a = t;
  510.                         rectCount++;
  511.                     } 
  512.                 } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  513.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  514.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  515.                     if(t.width > 0 && t.height > 0) {
  516.                         a = t;
  517.                         rectCount++;
  518.                     } 
  519.                 } else {
  520.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  521.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width),
  522.                                 (rectB.y + rectB.height) - rectA.y);
  523.                     if(t.width > 0 && t.height > 0) {
  524.                         a = new Rectangle(t);
  525.                         rectCount++;
  526.                     }
  527.                     
  528.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  529.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  530.                     if(t.width > 0 && t.height > 0) {
  531.                         b = new Rectangle(t);
  532.                         rectCount++;
  533.                     }
  534.                 }
  535.             } else if (rectB.x <= rectA.x && (rectB.y + rectB.height) >= (rectA.y + rectA.height)) {
  536.                 if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
  537.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  538.                     if(t.width > 0 && t.height > 0) {
  539.                         a = t;
  540.                         rectCount++;
  541.                     }
  542.                 } else {
  543.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  544.                     if(t.width > 0 && t.height > 0) {
  545.                         a = new Rectangle(t);
  546.                         rectCount++;
  547.                     }
  548.                     t.setBounds((rectB.x + rectB.width), rectB.y,
  549.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width),
  550.                                 (rectA.y + rectA.height) - rectB.y);
  551.                     if(t.width > 0 && t.height > 0) {
  552.                         b = new Rectangle(t);
  553.                         rectCount++;
  554.                     }
  555.                 }
  556.             } else if (rectB.x <= rectA.x) {
  557.                 if ((rectB.x + rectB.width) >= (rectA.x + rectA.width)) {
  558.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  559.                     if(t.width>0 && t.height > 0) {
  560.                         a = new Rectangle(t);
  561.                         rectCount++;
  562.                     }
  563.                 
  564.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  565.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  566.                     if(t.width > 0 && t.height > 0) {
  567.                         b = new Rectangle(t);
  568.                         rectCount++;
  569.                     }
  570.                 } else {
  571.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  572.                     if(t.width > 0 && t.height > 0) {
  573.                         a = new Rectangle(t);
  574.                         rectCount++;
  575.                     }
  576.  
  577.                     t.setBounds((rectB.x + rectB.width), rectB.y,
  578.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width),
  579.                                 rectB.height);
  580.                     if(t.width > 0 && t.height > 0) {
  581.                         b = new Rectangle(t);
  582.                         rectCount++;
  583.                     }
  584.                     
  585.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  586.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  587.                     if(t.width > 0 && t.height > 0) {
  588.                         c = new Rectangle(t);
  589.                         rectCount++;
  590.                     }
  591.                 }
  592.             } else if (rectB.x <= (rectA.x + rectA.width) && (rectB.x + rectB.width) > (rectA.x + rectA.width)) {
  593.                 if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  594.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  595.                     if(t.width > 0 && t.height > 0) {
  596.                         a = t;
  597.                         rectCount++;
  598.                     }
  599.                 } else if (rectB.y <= rectA.y) {
  600.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x,
  601.                                 (rectB.y + rectB.height) - rectA.y);
  602.                     if(t.width > 0 && t.height > 0) {
  603.                         a = new Rectangle(t);
  604.                         rectCount++;
  605.                     }
  606.  
  607.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.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.                 } else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  614.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  615.                     if(t.width > 0 && t.height > 0) {
  616.                         a = new Rectangle(t);
  617.                         rectCount++;
  618.                     }
  619.  
  620.                     t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
  621.                                 (rectA.y + rectA.height) - rectB.y);
  622.                     if(t.width > 0 && t.height > 0) {
  623.                         b = new Rectangle(t);
  624.                         rectCount++;
  625.                     }
  626.                 } else {
  627.                     t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
  628.                     if(t.width > 0 && t.height > 0) {
  629.                         a = new Rectangle(t);
  630.                         rectCount++;
  631.                     }
  632.  
  633.                     t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
  634.                                 rectB.height);
  635.                     if(t.width > 0 && t.height > 0) {
  636.                         b = new Rectangle(t);
  637.                         rectCount++;
  638.                     }
  639.  
  640.                     t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
  641.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  642.                     if(t.width > 0 && t.height > 0) {
  643.                         c = new Rectangle(t);
  644.                         rectCount++;
  645.                     }
  646.                 }
  647.             } else if (rectB.x >= rectA.x && (rectB.x + rectB.width) <= (rectA.x + rectA.width)) {
  648.                 if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
  649.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  650.                     if(t.width > 0 && t.height > 0) {
  651.                         a = new Rectangle(t);
  652.                         rectCount++;
  653.                     }
  654.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  655.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  656.                     if(t.width > 0 && t.height > 0) {
  657.                         b = new Rectangle(t);
  658.                         rectCount++;
  659.                     }
  660.                 } else if (rectB.y <= rectA.y) {
  661.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  662.                     if(t.width > 0 && t.height > 0) {
  663.                         a = new Rectangle(t);
  664.                         rectCount++;
  665.                     }
  666.  
  667.                     t.setBounds(rectB.x, (rectB.y + rectB.height),
  668.                                 rectB.width,
  669.                                 (rectA.y + rectA.height) - (rectB.y + rectB.height));
  670.                     if(t.width > 0 && t.height > 0) {
  671.                         b = new Rectangle(t);
  672.                         rectCount++;
  673.                     }
  674.  
  675.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  676.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  677.                     if(t.width > 0 && t.height > 0) {
  678.                         c = new Rectangle(t);
  679.                         rectCount++;
  680.                     }
  681.                 } else {
  682.                     t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
  683.                     if(t.width > 0 && t.height > 0) {
  684.                         a = new Rectangle(t);
  685.                         rectCount++;
  686.                     }
  687.  
  688.                     t.setBounds(rectB.x, rectA.y, rectB.width,
  689.                                 rectB.y - rectA.y);
  690.                     if(t.width > 0 && t.height > 0) {
  691.                         b = new Rectangle(t);
  692.                         rectCount++;
  693.                     }
  694.  
  695.                     t.setBounds((rectB.x + rectB.width), rectA.y,
  696.                                 (rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
  697.                     if(t.width > 0 && t.height > 0) {
  698.                         c = new Rectangle(t);
  699.                         rectCount++;
  700.                     }
  701.                 }
  702.             }
  703.         }
  704.  
  705.         result = new Rectangle[rectCount];
  706.         rectCount = 0;
  707.         if(a != null)
  708.             result[rectCount++] = a;
  709.         if(b != null)
  710.             result[rectCount++] = b;
  711.         if(c != null)
  712.             result[rectCount++] = c;
  713.         if(d != null)
  714.             result[rectCount++] = d;
  715.         return result;
  716.     }    
  717.     
  718.     public static boolean isLeftMouseButton(MouseEvent anEvent) {
  719.         return ((anEvent.getModifiers() & InputEvent.BUTTON1_MASK) == InputEvent.BUTTON1_MASK ||
  720.         (anEvent.getModifiers()  == 0));/*PENDING(ARNAUD) this is to workaround a bug on Solaris */
  721.     }
  722.     
  723.     public static boolean isMiddleMouseButton(MouseEvent anEvent) {
  724.         return ((anEvent.getModifiers() & InputEvent.BUTTON2_MASK) == InputEvent.BUTTON2_MASK);
  725.     }
  726.  
  727.     public static boolean isRightMouseButton(MouseEvent anEvent) {
  728.         return ((anEvent.getModifiers() & InputEvent.BUTTON3_MASK) == InputEvent.BUTTON3_MASK);
  729.     }
  730.  
  731.     /*
  732.      * Returns whether this is being run on a JDK 1.2 or later VM.
  733.      * This is a system-wide, rather than AppContext-wide, state.
  734.      */
  735.     /*package-private*/ static boolean is1dot2 = true;
  736.     
  737.     static {
  738.         try {
  739.             // Test if method introduced in 1.2 is available.
  740.             Method m = Toolkit.class.getMethod("getMaximumCursorColors", null);
  741.             is1dot2 = (m != null); 
  742.         } catch (NoSuchMethodException e) {
  743.             is1dot2 = false;
  744.         }
  745.     }
  746.  
  747.     public static int computeStringWidth(FontMetrics fm,String str) {
  748.         int w[] = fm.getWidths();
  749.         int i,c;
  750.         int result = 0;
  751.         char ch;
  752.         for(i=0,c=str.length() ; i < c ; i++) {
  753.             ch = str.charAt(i);
  754.             if(ch > 255)
  755.                 return fm.stringWidth(str);
  756.             else
  757.                 result += w[(int)ch];
  758.         }
  759.         return result;
  760.     }
  761.  
  762.     /** 
  763.      * Compute and return the location of the icons origin, the 
  764.      * location of origin of the text baseline, and a possibly clipped
  765.      * version of the compound labels string.  Locations are computed
  766.      * relative to the viewR rectangle. 
  767.      */
  768.  
  769.     public static String layoutCompoundLabel(
  770.         FontMetrics fm,
  771.         String text,
  772.         Icon icon,
  773.     int verticalAlignment,
  774.     int horizontalAlignment,
  775.     int verticalTextPosition,
  776.     int horizontalTextPosition,
  777.         Rectangle viewR, 
  778.     Rectangle iconR, 
  779.     Rectangle textR,
  780.     int textIconGap)
  781.     {
  782.     /* Initialize the icon bounds rectangle iconR.
  783.      */
  784.  
  785.     if (icon != null) {
  786.         iconR.width = icon.getIconWidth();
  787.         iconR.height = icon.getIconHeight();
  788.     } 
  789.     else {
  790.         iconR.width = iconR.height = 0;
  791.     }
  792.  
  793.     /* Initialize the text bounds rectangle textR.  If a null 
  794.      * or and empty String was specified we substitute "" here 
  795.      * and use 0,0,0,0 for textR.
  796.      */
  797.  
  798.     boolean textIsEmpty = (text == null) || text.equals("");
  799.  
  800.     if (textIsEmpty) {
  801.         textR.width = textR.height = 0;
  802.         text = "";
  803.     }
  804.     else {
  805.         textR.width = computeStringWidth(fm,text);
  806.         textR.height = fm.getHeight();
  807.     }
  808.  
  809.     /* Unless both text and icon are non-null, we effectively ignore
  810.      * the value of textIconGap.  The code that follows uses the
  811.      * value of gap instead of textIconGap.
  812.      */
  813.  
  814.     int gap = (textIsEmpty || (icon == null)) ? 0 : textIconGap;
  815.     
  816.     if (!textIsEmpty) {
  817.  
  818.         /* If the label text string is too wide to fit within the available
  819.          * space "..." and as many characters as will fit will be 
  820.          * displayed instead.  
  821.          */
  822.  
  823.         int availTextWidth;
  824.  
  825.         if (horizontalTextPosition == CENTER) {
  826.         availTextWidth = viewR.width;
  827.         }
  828.         else {
  829.         availTextWidth = viewR.width - (iconR.width + gap);
  830.         }
  831.  
  832.  
  833.         if (textR.width > availTextWidth) {
  834.         String clipString = "...";
  835.         int totalWidth = computeStringWidth(fm,clipString);
  836.         int nChars;
  837.         for(nChars = 0; nChars < text.length(); nChars++) {
  838.             totalWidth += fm.charWidth(text.charAt(nChars));
  839.             if (totalWidth > availTextWidth) {
  840.             break;
  841.             }
  842.         }
  843.         text = text.substring(0, nChars) + clipString;
  844.         textR.width = computeStringWidth(fm,text);
  845.         }
  846.     }
  847.  
  848.  
  849.     /* Compute textR.x,y given the verticalTextPosition and 
  850.      * horizontalTextPosition properties 
  851.      */
  852.  
  853.     if (verticalTextPosition == TOP) {
  854.         if (horizontalTextPosition != CENTER) {
  855.         textR.y = 0;
  856.         }
  857.         else {
  858.         textR.y = -(textR.height + gap);
  859.         }
  860.     }
  861.     else if (verticalTextPosition == CENTER) { 
  862.         textR.y = (iconR.height / 2) - (textR.height / 2);
  863.     }
  864.     else { // (verticalTextPosition == BOTTOM)
  865.         if (horizontalTextPosition != CENTER) {
  866.         textR.y = iconR.height - textR.height;
  867.         }
  868.         else {
  869.         textR.y = (iconR.height + gap);
  870.         }
  871.     }
  872.  
  873.     if (horizontalTextPosition == LEFT) {
  874.         textR.x = -(textR.width + gap);
  875.     }
  876.     else if (horizontalTextPosition == CENTER) { 
  877.         textR.x = (iconR.width / 2) - (textR.width / 2);
  878.     }
  879.     else { // (verticalTextPosition == RIGHT)
  880.         textR.x = (iconR.width + gap);
  881.     }
  882.  
  883.     /* labelR is the rectangle that contains iconR and textR.
  884.      * Move it to its proper position given the labelAlignment
  885.      * properties.
  886.      */
  887.  
  888.     Rectangle labelR = iconR.union(textR);
  889.     int dx, dy;
  890.  
  891.     if (verticalAlignment == TOP) {
  892.         dy = viewR.y - labelR.y;
  893.     }
  894.     else if (verticalAlignment == CENTER) {
  895.         dy = (viewR.y + (viewR.height / 2)) - (labelR.y + (labelR.height / 2));
  896.     }
  897.     else { // (verticalAlignment == BOTTOM)
  898.         dy = (viewR.y + viewR.height) - (labelR.y + labelR.height);
  899.     }
  900.  
  901.     if (horizontalAlignment == LEFT) {
  902.         dx = viewR.x - labelR.x;
  903.     }
  904.     else if (horizontalAlignment == CENTER) {
  905.         dx = (viewR.x + (viewR.width / 2)) - (labelR.x + (labelR.width / 2));
  906.     }
  907.     else { // (horizontalAlignment == RIGHT)
  908.         dx = (viewR.x + viewR.width) - (labelR.x + labelR.width);
  909.     }
  910.  
  911.     /* Translate textR and glypyR by dx,dy.  
  912.      */
  913.  
  914.     textR.x += dx;
  915.     textR.y += dy;
  916.  
  917.     iconR.x += dx;
  918.     iconR.y += dy;
  919.  
  920.     return text;
  921.     }
  922.  
  923.  
  924.     /** 
  925.      * Paint a component c on an abitrary graphics g in the 
  926.      * specified rectangle.  The component is reparented to a private
  927.      * container (whose parent becomes p) which prevents c.validate() and
  928.      * and c.repaint() calls from propogating up the tree.  The intermediate
  929.      * container has no other effect.
  930.      */
  931.      
  932.     public static void paintComponent(Graphics g, Component c, Container p, int x, int y, int w, int h) {
  933.     getCellRendererPane(c, p).paintComponent(g, c, p, x, y, w, h,false);
  934.     }
  935.  
  936.     public static void paintComponent(Graphics g, Component c, Container p, Rectangle r) {
  937.     paintComponent(g, c, p, r.x, r.y, r.width, r.height);
  938.     }
  939.  
  940.  
  941.     /**
  942.      * Ensure that cell renderer c has a ComponentShell parent and that
  943.      * the shells parent is p.
  944.      */
  945.     private static CellRendererPane getCellRendererPane(Component c, Container p) {
  946.     Container shell = c.getParent();
  947.     if (shell instanceof CellRendererPane) {
  948.         if (shell.getParent() != p) {
  949.         p.add(shell);
  950.         }
  951.     } else {
  952.         shell = new CellRendererPane();
  953.         shell.add(c);
  954.         p.add(shell);
  955.     }
  956.     return (CellRendererPane)shell;
  957.     }
  958.  
  959.     /** 
  960.      * A simple minded look and feel change: ask each node in the tree
  961.      * to updateUI(), i.e. to initialize its UI property with the
  962.      * current look and feel.
  963.      */
  964.     public static void updateComponentTreeUI(Component c) {
  965.         updateComponentTreeUI0(c);
  966.         c.invalidate();
  967.         c.validate();
  968.         c.repaint();
  969.     }
  970.  
  971.     private static void updateComponentTreeUI0(Component c) {
  972.     if (c instanceof JComponent) {
  973.         ((JComponent) c).updateUI();
  974.     }
  975.     Component[] children = null;
  976.     if (c instanceof JMenu) {
  977.         children = ((JMenu)c).getMenuComponents();
  978.     }
  979.     else if (c instanceof Container) {
  980.         children = ((Container)c).getComponents();
  981.     }
  982.     if (children != null) {
  983.         for(int i = 0; i < children.length; i++) {
  984.         updateComponentTreeUI0(children[i]);
  985.         }
  986.     }
  987.     }
  988.  
  989.   static class TimerInvoker implements ActionListener {
  990.     Runnable r;
  991.     Timer t;
  992.     public Object lock = new Object();
  993.  
  994.     TimerInvoker(Runnable obj) {
  995.       this(obj,true);
  996.     }
  997.  
  998.     TimerInvoker(Runnable obj,boolean start) {
  999.       t = new Timer(0,this);
  1000.       r = obj;
  1001.       t.setRepeats(false);
  1002.       if(start)
  1003.     t.start();
  1004.     }
  1005.  
  1006.     public void start() {
  1007.       t.start();
  1008.     }
  1009.  
  1010.     public void actionPerformed(ActionEvent e) {
  1011.       try {
  1012.     r.run();
  1013.       } catch(Exception ex) {
  1014.       }
  1015.       synchronized(lock) {
  1016.           lock.notifyAll();
  1017.       }
  1018.     }
  1019.   }
  1020.  
  1021.     /**
  1022.      * --- Accessibility Support ---
  1023.      *
  1024.      */
  1025.    
  1026.     /**
  1027.      * Get the index of this object in its accessible parent.
  1028.      *
  1029.      * @return -1 of this object does not have an accessible parent.
  1030.      * Otherwise, the index of the child in its accessible parent.
  1031.      */
  1032.     public static int getAccessibleIndexInParent(Component c) {
  1033.         int index = -1;
  1034.         Container parent = c.getParent();
  1035.         if (parent != null) {
  1036.             Component ca[] = parent.getComponents();
  1037.             for (int i = 0; i < ca.length; i++) {
  1038.         if (ca[i] instanceof Accessible) {
  1039.             index++;
  1040.         }
  1041.                 if (c.equals(ca[i])) {
  1042.             return index;
  1043.         }
  1044.             }
  1045.         }
  1046.     return -1;
  1047.     }
  1048.  
  1049.     /**
  1050.      * Returns the Accessible child contained at the local coordinate
  1051.      * Point, if one exists.
  1052.      *
  1053.      * @return the Accessible at the specified location, if it exists
  1054.      */
  1055.     public static Accessible getAccessibleAt(Component c, Point p) {
  1056.     if (c instanceof Accessible) {
  1057.             Accessible a = (Accessible) c;
  1058.         if (a != null) {
  1059.         AccessibleContext ac = a.getAccessibleContext();
  1060.         if (ac != null) {
  1061.             AccessibleComponent acmp;
  1062.             Point location;
  1063.             int nchildren = ac.getAccessibleChildrenCount();
  1064.             for (int i=0; i < nchildren; i++) {
  1065.             a = ac.getAccessibleChild(i);
  1066.             if ((a != null)) {
  1067.                 ac = a.getAccessibleContext();
  1068.                 if (ac != null) {
  1069.                 acmp = ac.getAccessibleComponent();
  1070.                 if ((acmp != null) && (acmp.isShowing())) {
  1071.                     location = acmp.getLocation();
  1072.                     Point np = new Point(p.x-location.x, 
  1073.                              p.y-location.y);
  1074.                     if (acmp.contains(np)){
  1075.                     return a;
  1076.                     }
  1077.                 }
  1078.                 }
  1079.             }
  1080.             }
  1081.                 }
  1082.             }
  1083.             return (Accessible) c;
  1084.     } else {
  1085.         Component ret = c;
  1086.         if (!c.contains(p.x,p.y)) {
  1087.         ret = null;
  1088.         } else if (c instanceof Container) {
  1089.         Container cnt = (Container) c;
  1090.         int ncomponents = cnt.getComponentCount();
  1091.         for (int i=0; i < ncomponents; i++) {
  1092.             Component comp = cnt.getComponent(i);
  1093.             if ((comp != null) && comp.isShowing()) {
  1094.             Point location = comp.getLocation();
  1095.             if (comp.contains(p.x-location.x,p.y-location.y)) {
  1096.                 ret = comp;
  1097.             }
  1098.             }
  1099.         }
  1100.         }
  1101.         if (ret instanceof Accessible) {
  1102.         return (Accessible) ret;
  1103.         }
  1104.     }
  1105.     return null;
  1106.     }
  1107.  
  1108.     /**
  1109.      * Get the state of this object.
  1110.      *
  1111.      * @return an instance of AccessibleStateSet containing the current state 
  1112.      * set of the object
  1113.      * @see AccessibleState
  1114.      */
  1115.     public static AccessibleStateSet getAccessibleStateSet(Component c) {
  1116.     AccessibleStateSet states = new AccessibleStateSet();
  1117.         if (c.isEnabled()) {
  1118.             states.add(AccessibleState.ENABLED);
  1119.         }
  1120.         if (c.isFocusTraversable()) {
  1121.             states.add(AccessibleState.FOCUSABLE);
  1122.         }
  1123.         if (c.isVisible()) {
  1124.             states.add(AccessibleState.VISIBLE);
  1125.         }
  1126.         if (c.isShowing()) {
  1127.             states.add(AccessibleState.SHOWING);
  1128.         }
  1129.     // [[[FIXME:  WDW - for JDK1.2 this code can be replaced with
  1130.     //            c.hasFocus()]]]
  1131.         for (Container p = c.getParent(); p != null; p = p.getParent()) {
  1132.             if (p instanceof Window) {
  1133.         if (((Window)p).getFocusOwner() == c) {
  1134.                 states.add(AccessibleState.FOCUSED);
  1135.         }
  1136.         }
  1137.         }
  1138.         if (c instanceof Accessible) {
  1139.         AccessibleContext ac = ((Accessible) c).getAccessibleContext();
  1140.         if (ac != null) {
  1141.         Accessible ap = ac.getAccessibleParent();
  1142.         if (ap != null) {
  1143.                 AccessibleContext pac = ap.getAccessibleContext();
  1144.             if (pac != null) {
  1145.                 AccessibleSelection as = pac.getAccessibleSelection();
  1146.                 if (as != null) {
  1147.                 states.add(AccessibleState.SELECTABLE);
  1148.                     int i = ac.getAccessibleIndexInParent();
  1149.                 if (i >= 0) {
  1150.                     if (as.isAccessibleChildSelected(i)) {
  1151.                     states.add(AccessibleState.SELECTED);
  1152.                     }
  1153.                 }
  1154.             }
  1155.             }
  1156.         }
  1157.         }
  1158.     }
  1159.     if (c instanceof JComponent) {
  1160.         if (((JComponent) c).isOpaque()) {
  1161.         states.add(AccessibleState.OPAQUE);
  1162.         }
  1163.     }
  1164.     return states;
  1165.     }
  1166.  
  1167.     /**
  1168.      * Returns the number of accessible children in the object.  If all
  1169.      * of the children of this object implement Accessible, than this
  1170.      * method should return the number of children of this object.
  1171.      *
  1172.      * @return the number of accessible children in the object.
  1173.      */
  1174.     public static int getAccessibleChildrenCount(Component c) {
  1175.     int count = 0;
  1176.     if (c instanceof Container) {
  1177.         Component[] children = ((Container) c).getComponents();
  1178.         for (int i = 0; i < children.length; i++) {
  1179.             if (children[i] instanceof Accessible) {
  1180.             count++;
  1181.             }
  1182.         }
  1183.     }
  1184.     return count;
  1185.     }
  1186.  
  1187.     /**
  1188.      * Return the nth Accessible child of the object.  
  1189.      *
  1190.      * @param i zero-based index of child
  1191.      * @return the nth Accessible child of the object
  1192.      */
  1193.     public static Accessible getAccessibleChild(Component c, int i) {
  1194.     if (c instanceof Container) {
  1195.             Component[] children = ((Container) c).getComponents();
  1196.             int count = 0;
  1197.             for (int j = 0; j < children.length; j++) {
  1198.                 if (children[j] instanceof Accessible) {
  1199.                     if (count == i) {
  1200.                    return (Accessible) children[j];
  1201.             } else {
  1202.                 count++;
  1203.             }
  1204.                 }
  1205.             }
  1206.     }
  1207.         return null;
  1208.     }
  1209.  
  1210.     /**
  1211.      * Return the child component which has focus, if any.  The HotJava
  1212.      * SecurityManager forbids applet access to getFocusOwner(), so if the
  1213.      * component is an applet, we check whether a JComponent has focus.
  1214.      * Non-Swing components in an applet on HotJava are out-of-luck,
  1215.      * unfortunately.
  1216.      */
  1217.     public static Component findFocusOwner(Component c) {
  1218.         if (c instanceof Window) {
  1219.             return ((Window)c).getFocusOwner();
  1220.         }
  1221.  
  1222.         if (c instanceof JComponent && ((JComponent)c).hasFocus()) {
  1223.             return c;
  1224.         }
  1225.         if (c instanceof Container) {
  1226.             int n = ((Container)c).countComponents();
  1227.             for (int i = 0; i < n; i++) {
  1228.                 Component focusOwner = 
  1229.                     findFocusOwner(((Container)c).getComponent(i));
  1230.                 if (focusOwner != null) {
  1231.                     return focusOwner;
  1232.                 }
  1233.             }
  1234.             return null;
  1235.         } else {
  1236.             return null;  // Component doesn't have hasFocus().
  1237.         }
  1238.     }
  1239.  
  1240.     /**
  1241.      * Return the JRootPane ancestor for a Component 
  1242.      * 
  1243.      * Return null if no JRootPane is found.
  1244.      */
  1245.     public static JRootPane getRootPane(Component c) {
  1246.         Container cnt;
  1247.         for(cnt = c.getParent() ; cnt != null ; cnt = cnt.getParent())
  1248.             if(cnt instanceof JRootPane)
  1249.                 return (JRootPane)cnt;
  1250.         return null;
  1251.     }
  1252.  
  1253.     // Don't use String, as it's not guaranteed to be unique in a Hashtable.
  1254.     private static final Object sharedOwnerFrameKey = 
  1255.        new StringBuffer("SwingUtilities.sharedOwnerFrame");
  1256.  
  1257.     /**
  1258.      * Returns a toolkit-private, shared, invisible Frame
  1259.      * to be the owner for JDialogs and JWindows created with 
  1260.      * null owners.
  1261.      */
  1262.     static Frame getSharedOwnerFrame() {
  1263.         Frame sharedOwnerFrame = 
  1264.             (Frame)SwingUtilities.appContextGet(sharedOwnerFrameKey);
  1265.         if (sharedOwnerFrame == null) {
  1266.             sharedOwnerFrame = new Frame() {
  1267.                 public void show() {
  1268.                     // This frame can never be shown
  1269.                 }
  1270.                 public synchronized void dispose() {
  1271.                     try {
  1272.                         getToolkit().getSystemEventQueue();    
  1273.                         super.dispose();
  1274.                     } catch (Exception e) {
  1275.                         // untrusted code not allowed to dispose
  1276.                     }
  1277.                 }
  1278.             };
  1279.             SwingUtilities.appContextPut(sharedOwnerFrameKey,
  1280.                                          sharedOwnerFrame);
  1281.         }
  1282.         return sharedOwnerFrame;
  1283.     }
  1284.  
  1285.     // The following static var and methods are a temporary
  1286.     // workaround for a Solaris bug where disposing modal dialogs
  1287.     // can sometimes cause a segmentation violation. Once this
  1288.     // AWT bug is fixed and available in browsers, we can remove
  1289.     // this workaround.
  1290.     private static final Object dialogsKey = 
  1291.         new StringBuffer("SwingUtilities.dialogs");
  1292.  
  1293.     static JDialog getRecycledModalDialog(Frame frame, String title) {
  1294.         Vector dialogs = (Vector)SwingUtilities.appContextGet(dialogsKey);
  1295.         if (dialogs == null) {
  1296.             dialogs = new Vector();
  1297.             SwingUtilities.appContextPut(dialogsKey, dialogs);
  1298.         }
  1299.         JDialog dialog = null;
  1300.         synchronized(dialogs) {
  1301.             for(int i = 0; i < dialogs.size(); i++) {
  1302.                 dialog = (JDialog)dialogs.elementAt(i);
  1303.                 if (dialog.getParent() == frame) {
  1304.                     //System.out.println("Found available dialog: "+dialog);
  1305.                     dialogs.removeElement(dialog);
  1306.                     dialog.setTitle(title);
  1307.                     return dialog;
  1308.                 }
  1309.             }       
  1310.             dialog = new JDialog(frame, title, true);
  1311.             //System.out.println("Created new dialog: "+dialog);
  1312.         }
  1313.         return dialog;
  1314.     }
  1315.  
  1316.     static void recycleModalDialog(JDialog dialog) {
  1317.         Vector dialogs = (Vector)SwingUtilities.appContextGet(dialogsKey);
  1318.         synchronized(dialogs) {
  1319.             dialog.getContentPane().removeAll();
  1320.             dialogs.addElement(dialog);
  1321.         }
  1322.     }
  1323.  
  1324.     /* Don't make these AppContext accessors public or protected --
  1325.      * since AppContext is in sun.awt in 1.2, we shouldn't expose it
  1326.      * even indirectly with a public API.
  1327.      */
  1328.     static Object appContextGet(Object key) {
  1329.         sun.awt.AppContext ac = 
  1330.             sun.awt.AppContext.getAppContext();
  1331.         return ac.get(key);
  1332.     }
  1333.  
  1334.     static void appContextPut(Object key, Object value) {
  1335.         sun.awt.AppContext ac = 
  1336.             sun.awt.AppContext.getAppContext();
  1337.         ac.put(key, value);
  1338.     }
  1339.  
  1340.     static void appContextRemove(Object key) {
  1341.         sun.awt.AppContext.getAppContext().remove(key);
  1342.     }
  1343. }
  1344.