/*
 
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 
*
 
* This code is free software; you can redistribute it and/or modify it
 
* under the terms of the GNU General Public License version 2 only, as
 
* published by the Free Software Foundation.
  
Oracle designates this
 
* particular file as subject to the "Classpath" exception as provided
 
* by Oracle in the LICENSE file that accompanied this code.
 
*
 
* This code is distributed in the hope that it will be useful, but WITHOUT
 
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
* FITNESS FOR A PARTICULAR PURPOSE.
  
See the GNU General Public License
 
* version 2 for more details (a copy is included in the LICENSE file that
 
* accompanied this code).
 
*
 
* You should have received a copy of the GNU General Public License version
 
* 2 along with this work; if not, write to the Free Software Foundation,
 
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 
*
 
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 
* or visit www.oracle.com if you need additional information or have any
 
* questions.
 
*/
package javax.swing;

import sun.reflect.misc.ReflectUtil;
import sun.swing.SwingUtilities2;
import sun.swing.UIAction;

import java.applet.*;

import java.awt.*;
import java.awt.event.*;
import java.awt.dnd.DropTarget;

import java.lang.reflect.*;

import javax.accessibility.*;
import javax.swing.event.MenuDragMouseEvent;
import javax.swing.plaf.UIResource;
import javax.swing.text.View;
import java.security.AccessController;
import sun.security.action.GetPropertyAction;

import sun.awt.AppContext;
import sun.awt.AWTAccessor;
import sun.awt.AWTAccessor.MouseEventAccessor;

/**
 
* A collection of utility methods for Swing.
 
*
 
* @author unknown
 
*/

public class SwingUtilities implements SwingConstants
{
    
// These states are system-wide, rather than AppContext wide.
    
private static boolean canAccessEventQueue = false;
    
private static boolean eventQueueTested = false;

    
/**
     
* Indicates if we should change the drop target when a
     
* {@code TransferHandler} is set.
     
*/

    
private static boolean suppressDropSupport;

    
/**
     
* Indiciates if we've checked the system property for suppressing
     
* drop support.
     
*/

    
private static boolean checkedSuppressDropSupport;


    
/**
     
* Returns true if <code>setTransferHandler</code> should change the
     
* <code>DropTarget</code>.
     
*/

    
private static boolean getSuppressDropTarget() {
        
if (!checkedSuppressDropSupport) {
            
suppressDropSupport = Boolean.valueOf(
                
AccessController.doPrivileged(
                    
new GetPropertyAction("suppressSwingDropSupport")));
            
checkedSuppressDropSupport = true;
        
}
        
return suppressDropSupport;
    
}

    
/**
     
* Installs a {@code DropTarget} on the component as necessary for a
     
* {@code TransferHandler} change.
     
*/

    
static void installSwingDropTargetAsNecessary(Component c,
                                                         
TransferHandler t) {

        
if (!getSuppressDropTarget()) {
            
DropTarget dropHandler = c.getDropTarget();
            
if ((dropHandler == null) || (dropHandler instanceof UIResource)) {
                
if (t == null) {
                    
c.setDropTarget(null);
                
} else if (!GraphicsEnvironment.isHeadless()) {
                    
c.setDropTarget(new TransferHandler.SwingDropTarget(c));
                
}
            
}
        
}
    
}

    
/**
     
* Return true if <code>a</code> contains <code>b</code>
     
*/
    
public static final boolean isRectangleContainingRectangle(Rectangle a,Rectangle b) {
        
return b.x >= a.x && (b.x + b.width) <= (a.x + a.width) &&
                
b.y >= a.y && (b.y + b.height) <= (a.y + a.height);
    
}

    
/**
     
* Return the rectangle (0,0,bounds.width,bounds.height) for the component <code>aComponent</code>
     
*/

    
public static Rectangle getLocalBounds(Component aComponent) {
        
Rectangle b = new Rectangle(aComponent.getBounds());
        
b.x = b.y = 0;
        
return b;
    
}


    
/**
     
* Returns the first <code>Window </code> ancestor of <code>c</code>, or
     
* {@code null} if <code>c</code> is not contained inside a <code>Window</code>.
     
*
     
* @param c <code>Component</code> to get <code>Window</code> ancestor
     
*
        
of.
     
* @return the first <code>Window </code> ancestor of <code>c</code>, or
     
*
         
{@code null} if <code>c</code> is not contained inside a
     
*
         
<code>Window</code>.
     
* @since 1.3
     
*/

    
public static Window getWindowAncestor(Component c) {
        
for(Container p = c.getParent(); p != null; p = p.getParent()) {
            
if (p instanceof Window) {
                
return (Window)p;
            
}
        
}
        
return null;
    
}

    
/**
     
* Converts the location <code>x</code> <code>y</code> to the
     
* parents coordinate system, returning the location.
     
*/

    
static Point convertScreenLocationToParent(Container parent,int x, int y) {
        
for (Container p = parent; p != null; p = p.getParent()) {
            
if (p instanceof Window) {
                
Point point = new Point(x, y);

                
SwingUtilities.convertPointFromScreen(point, parent);
                
return point;
            
}
        
}
        
throw new Error("convertScreenLocationToParent: no window ancestor");
    
}

    
/**
     
* Convert a <code>aPoint</code> in <code>source</code> coordinate system to
     
* <code>destination</code> coordinate system.
     
* If <code>source</code> is {@code null}, <code>aPoint</code> is assumed to be in <code>destination</code>'s
     
* root component coordinate system.
     
* If <code>destination</code> is {@code null}, <code>aPoint</code> will be converted to <code>source</code>'s
     
* root component coordinate system.
     
* If both <code>source</code> and <code>destination</code> are {@code null}, return <code>aPoint</code>
     
* without any conversion.
     
*/

    
public static Point convertPoint(Component source,Point aPoint,Component destination) {
        
Point p;

        
if(source == null && destination == null)
            
return aPoint;
        
if(source == null) {
            
source = getWindowAncestor(destination);
            
if(source == null)
                
throw new Error("Source component not connected to component tree hierarchy");
        
}
        
p = new Point(aPoint);
        
convertPointToScreen(p,source);
        
if(destination == null) {
            
destination = getWindowAncestor(source);
            
if(destination == null)
                
throw new Error("Destination component not connected to component tree hierarchy");
        
}
        
convertPointFromScreen(p,destination);
        
return p;
    
}

    
/**
     
* Convert the point <code>(x,y)</code> in <code>source</code> coordinate system to
     
* <code>destination</code> coordinate system.
     
* If <code>source</code> is {@code null}, <code>(x,y)</code> is assumed to be in <code>destination</code>'s
     
* root component coordinate system.
     
* If <code>destination</code> is {@code null}, <code>(x,y)</code> will be converted to <code>source</code>'s
     
* root component coordinate system.
     
* If both <code>source</code> and <code>destination</code> are {@code null}, return <code>(x,y)</code>
     
* without any conversion.
     
*/

    
public static Point convertPoint(Component source,int x, int y,Component destination) {
        
Point point = new Point(x,y);
        
return convertPoint(source,point,destination);
    
}

    
/**
     
* Convert the rectangle <code>aRectangle</code> in <code>source</code> coordinate system to
     
* <code>destination</code> coordinate system.
     
* If <code>source</code> is {@code null}, <code>aRectangle</code> is assumed to be in <code>destination</code>'s
     
* root component coordinate system.
     
* If <code>destination</code> is {@code null}, <code>aRectangle</code> will be converted to <code>source</code>'s
     
* root component coordinate system.
     
* If both <code>source</code> and <code>destination</code> are {@code null}, return <code>aRectangle</code>
     
* without any conversion.
     
*/

    
public static Rectangle convertRectangle(Component source,Rectangle aRectangle,Component destination) {
        
Point point = new Point(aRectangle.x,aRectangle.y);
        
point =
  
convertPoint(source,point,destination);
        
return new Rectangle(point.x,point.y,aRectangle.width,aRectangle.height);
    
}

    
/**
     
* Convenience method for searching above <code>comp</code> in the
     
* component hierarchy and returns the first object of class <code>c</code> it
     
* finds. Can return {@code null}, if a class <code>c</code> cannot be found.
     
*/

    
public static Container getAncestorOfClass(Class<?> c, Component comp)
    
{
        
if(comp == null || c == null)
            
return null;

        
Container parent = comp.getParent();
        
while(parent != null && !(c.isInstance(parent)))
            
parent = parent.getParent();
        
return parent;
    
}

    
/**
     
* Convenience method for searching above <code>comp</code> in the
     
* component hierarchy and returns the first object of <code>name</code> it
     
* finds. Can return {@code null}, if <code>name</code> cannot be found.
     
*/

    
public static Container getAncestorNamed(String name, Component comp) {
        
if(comp == null || name == null)
            
return null;

        
Container parent = comp.getParent();
        
while(parent != null && !(name.equals(parent.getName())))
            
parent = parent.getParent();
        
return parent;
    
}

    
/**
     
* Returns the deepest visible descendent Component of <code>parent</code>
     
* that contains the location <code>x</code>, <code>y</code>.
     
* If <code>parent</code> does not contain the specified location,
     
* then <code>null</code> is returned.
  
If <code>parent</code> is not a
     
* container, or none of <code>parent</code>'s visible descendents
     
* contain the specified location, <code>parent</code> is returned.
     
*
     
* @param parent the root component to begin the search
     
* @param x the x target location
     
* @param y the y target location
     
*/

    
public static Component getDeepestComponentAt(Component parent, int x, int y) {
        
if (!parent.contains(x, y)) {
            
return null;
        
}
        
if (parent instanceof Container) {
            
Component components[] = ((Container)parent).getComponents();
            
for (Component comp : components) {
                
if (comp != null && comp.isVisible()) {
                    
Point loc = comp.getLocation();
                    
if (comp instanceof Container) {
                        
comp = getDeepestComponentAt(comp, x - loc.x, y - loc.y);
                    
} else {
                        
comp = comp.getComponentAt(x - loc.x, y - loc.y);
                    
}
                    
if (comp != null && comp.isVisible()) {
                        
return comp;
                    
}
                
}
            
}
        
}
        
return parent;
    
}


    
/**
     
* Returns a MouseEvent similar to <code>sourceEvent</code> except that its x
     
* and y members have been converted to <code>destination</code>'s coordinate
     
* system.
  
If <code>source</code> is {@code null}, <code>sourceEvent</code> x and y members
     
* are assumed to be into <code>destination</code>'s root component coordinate system.
     
* If <code>destination</code> is <code>null</code>, the
     
* returned MouseEvent will be in <code>source</code>'s coordinate system.
     
* <code>sourceEvent</code> will not be changed. A new event is returned.
     
* the <code>source</code> field of the returned event will be set
     
* to <code>destination</code> if destination is non-{@code null}
     
* use the translateMouseEvent() method to translate a mouse event from
     
* one component to another without changing the source.
     
*/

    
public static MouseEvent convertMouseEvent(Component source,
                                               
MouseEvent sourceEvent,
                                               
Component destination) {
        
Point p = convertPoint(source,new Point(sourceEvent.getX(),
                                                
sourceEvent.getY()),
                               
destination);
        
Component newSource;

        
if(destination != null)
            
newSource = destination;
        
else
            
newSource = source;

        
MouseEvent newEvent;
        
if (sourceEvent instanceof MouseWheelEvent) {
            
MouseWheelEvent sourceWheelEvent = (MouseWheelEvent)sourceEvent;
            
newEvent = new MouseWheelEvent(newSource,
                                           
sourceWheelEvent.getID(),
                                           
sourceWheelEvent.getWhen(),
                                           
sourceWheelEvent.getModifiers()
                                                   
| sourceWheelEvent.getModifiersEx(),
                                           
p.x,p.y,
                                           
sourceWheelEvent.getXOnScreen(),
                                           
sourceWheelEvent.getYOnScreen(),
                                           
sourceWheelEvent.getClickCount(),
                                           
sourceWheelEvent.isPopupTrigger(),
                                           
sourceWheelEvent.getScrollType(),
                                           
sourceWheelEvent.getScrollAmount(),
                                           
sourceWheelEvent.getWheelRotation());
        
}
        
else if (sourceEvent instanceof MenuDragMouseEvent) {
            
MenuDragMouseEvent sourceMenuDragEvent = (MenuDragMouseEvent)sourceEvent;
            
newEvent = new MenuDragMouseEvent(newSource,
                                              
sourceMenuDragEvent.getID(),
                                              
sourceMenuDragEvent.getWhen(),
                                              
sourceMenuDragEvent.getModifiers()
                                                      
| sourceMenuDragEvent.getModifiersEx(),
                                              
p.x,p.y,
                                              
sourceMenuDragEvent.getXOnScreen(),
                                              
sourceMenuDragEvent.getYOnScreen(),
                                              
sourceMenuDragEvent.getClickCount(),
                                              
sourceMenuDragEvent.isPopupTrigger(),
                                              
sourceMenuDragEvent.getPath(),
                                              
sourceMenuDragEvent.getMenuSelectionManager());
        
}
        
else {
            
newEvent = new MouseEvent(newSource,
                                      
sourceEvent.getID(),
                                      
sourceEvent.getWhen(),
                                      
sourceEvent.getModifiers()
                                              
| sourceEvent.getModifiersEx(),
                                      
p.x,p.y,
                                      
sourceEvent.getXOnScreen(),
                                      
sourceEvent.getYOnScreen(),
                                      
sourceEvent.getClickCount(),
                                      
sourceEvent.isPopupTrigger(),
                                      
sourceEvent.getButton());
            
MouseEventAccessor meAccessor = AWTAccessor.getMouseEventAccessor();
            
meAccessor.setCausedByTouchEvent(newEvent,
                
meAccessor.isCausedByTouchEvent(sourceEvent));
        
}
        
return newEvent;
    
}


    
/**
     
* Convert a point from a component's coordinate system to
     
* screen coordinates.
     
*
     
* @param p
  
a Point object (converted to the new coordinate system)
     
* @param c
  
a Component object
     
*/

    
public static void convertPointToScreen(Point p,Component c) {
            
Rectangle b;
            
int x,y;

            
do {
                
if(c instanceof JComponent) {
                    
x = c.getX();
                    
y = c.getY();
                
} else if(c instanceof java.applet.Applet ||
                          
c instanceof java.awt.Window) {
                    
try {
                        
Point pp = c.getLocationOnScreen();
                        
x = pp.x;
                        
y = pp.y;
                    
} catch (IllegalComponentStateException icse) {
                        
x = c.getX();
                        
y = c.getY();
                    
}
                
} else {
                    
x = c.getX();
                    
y = c.getY();
                
}

                
p.x += x;
                
p.y += y;

                
if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
                    
break;
                
c = c.getParent();
            
} while(c != null);
        
}

    
/**
     
* Convert a point from a screen coordinates to a component's
     
* coordinate system
     
*
     
* @param p
  
a Point object (converted to the new coordinate system)
     
* @param c
  
a Component object
     
*/

    
public static void convertPointFromScreen(Point p,Component c) {
        
Rectangle b;
        
int x,y;

        
do {
            
if(c instanceof JComponent) {
                
x = c.getX();
                
y = c.getY();
            
}
  
else if(c instanceof java.applet.Applet ||
                       
c instanceof java.awt.Window) {
                
try {
                    
Point pp = c.getLocationOnScreen();
                    
x = pp.x;
                    
y = pp.y;
                
} catch (IllegalComponentStateException icse) {
                    
x = c.getX();
                    
y = c.getY();
                
}
            
} else {
                
x = c.getX();
                
y = c.getY();
            
}

            
p.x -= x;
            
p.y -= y;

            
if(c instanceof java.awt.Window || c instanceof java.applet.Applet)
                
break;
            
c = c.getParent();
        
} while(c != null);
    
}

    
/**
     
* Returns the first <code>Window </code> ancestor of <code>c</code>, or
     
* {@code null} if <code>c</code> is not contained inside a <code>Window</code>.
     
* <p>
     
* Note: This method provides the same functionality as
     
* <code>getWindowAncestor</code>.
     
*
     
* @param c <code>Component</code> to get <code>Window</code> ancestor
     
*
        
of.
     
* @return the first <code>Window </code> ancestor of <code>c</code>, or
     
*
         
{@code null} if <code>c</code> is not contained inside a
     
*
         
<code>Window</code>.
     
*/

    
public static Window windowForComponent(Component c) {
        
return getWindowAncestor(c);
    
}

    
/**
     
* Return <code>true</code> if a component <code>a</code> descends from a component <code>b</code>
     
*/

    
public static boolean isDescendingFrom(Component a,Component b) {
        
if(a == b)
            
return true;
        
for(Container p = a.getParent();p!=null;p=p.getParent())
            
if(p == b)
                
return true;
        
return false;
    
}


    
/**
     
* Convenience to calculate the intersection of two rectangles
     
* without allocating a new rectangle.
     
* If the two rectangles don't intersect,
     
* then the returned rectangle begins at (0,0)
     
* and has zero width and height.
     
*
     
* @param x
       
the X coordinate of the first rectangle's top-left point
     
* @param y
       
the Y coordinate of the first rectangle's top-left point
     
* @param width
   
the width of the first rectangle
     
* @param height
  
the height of the first rectangle
     
* @param dest
    
the second rectangle
     
*
     
* @return <code>dest</code>, modified to specify the intersection
     
*/

    
public static Rectangle computeIntersection(int x,int y,int width,int height,Rectangle dest) {
        
int x1 = (x > dest.x) ? x : dest.x;
        
int x2 = ((x+width) < (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
        
int y1 = (y > dest.y) ? y : dest.y;
        
int y2 = ((y + height) < (dest.y + dest.height) ? (y+height) : (dest.y + dest.height));

        
dest.x = x1;
        
dest.y = y1;
        
dest.width = x2 - x1;
        
dest.height = y2 - y1;

        
// If rectangles don't intersect, return zero'd intersection.
        
if (dest.width < 0 || dest.height < 0) {
            
dest.x = dest.y = dest.width = dest.height = 0;
        
}

        
return dest;
    
}

    
/**
     
* Convenience method that calculates the union of two rectangles
     
* without allocating a new rectangle.
     
*
     
* @param x the x-coordinate of the first rectangle
     
* @param y the y-coordinate of the first rectangle
     
* @param width the width of the first rectangle
     
* @param height the height of the first rectangle
     
* @param dest
  
the coordinates of the second rectangle; the union
     
*
    
of the two rectangles is returned in this rectangle
     
* @return the <code>dest</code> <code>Rectangle</code>
     
*/

    
public static Rectangle computeUnion(int x,int y,int width,int height,Rectangle dest) {
        
int x1 = (x < dest.x) ? x : dest.x;
        
int x2 = ((x+width) > (dest.x + dest.width)) ? (x+width) : (dest.x + dest.width);
        
int y1 = (y < dest.y) ? y : dest.y;
        
int y2 = ((y+height) > (dest.y + dest.height)) ? (y+height) : (dest.y + dest.height);

        
dest.x = x1;
        
dest.y = y1;
        
dest.width = (x2 - x1);
        
dest.height= (y2 - y1);
        
return dest;
    
}

    
/**
     
* Convenience returning an array of rect representing the regions within
     
* <code>rectA</code> that do not overlap with <code>rectB</code>. If the
     
* two Rects do not overlap, returns an empty array
     
*/

    
public static Rectangle[] computeDifference(Rectangle rectA,Rectangle rectB) {
        
if (rectB == null || !rectA.intersects(rectB) || isRectangleContainingRectangle(rectB,rectA)) {
            
return new Rectangle[0];
        
}

        
Rectangle t = new Rectangle();
        
Rectangle a=null,b=null,c=null,d=null;
        
Rectangle result[];
        
int rectCount = 0;

        
/* rectA contains rectB */
        
if (isRectangleContainingRectangle(rectA,rectB)) {
            
t.x = rectA.x; t.y = rectA.y; t.width = rectB.x - rectA.x; t.height = rectA.height;
            
if(t.width > 0 && t.height > 0) {
                
a = new Rectangle(t);
                
rectCount++;
            
}

            
t.x = rectB.x; t.y = rectA.y; t.width = rectB.width; t.height = rectB.y - rectA.y;
            
if(t.width > 0 && t.height > 0) {
                
b = new Rectangle(t);
                
rectCount++;
            
}

            
t.x = rectB.x; t.y = rectB.y + rectB.height; t.width = rectB.width;
            
t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
            
if(t.width > 0 && t.height > 0) {
                
c = new Rectangle(t);
                
rectCount++;
            
}

            
t.x = rectB.x + rectB.width; t.y = rectA.y; t.width = rectA.x + rectA.width - (rectB.x + rectB.width);
            
t.height = rectA.height;
            
if(t.width > 0 && t.height > 0) {
                
d = new Rectangle(t);
                
rectCount++;
            
}
        
} else {
            
/* 1 */
            
if (rectB.x <= rectA.x && rectB.y <= rectA.y) {
                
if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {

                    
t.x = rectA.x; t.y = rectB.y + rectB.height;
                    
t.width = rectA.width; t.height = rectA.y + rectA.height - (rectB.y + rectB.height);
                    
if(t.width > 0 && t.height > 0) {
                        
a = t;
                        
rectCount++;
                    
}
                
} else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
                    
t.setBounds((rectB.x + rectB.width), rectA.y,
                                
(rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
                    
if(t.width > 0 && t.height > 0) {
                        
a = t;
                        
rectCount++;
                    
}
                
} else {
                    
t.setBounds((rectB.x + rectB.width), rectA.y,
                                
(rectA.x + rectA.width) - (rectB.x + rectB.width),
                                
(rectB.y + rectB.height) - rectA.y);
                    
if(t.width > 0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
                                
(rectA.y + rectA.height) - (rectB.y + rectB.height));
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}
                
}
            
} else if (rectB.x <= rectA.x && (rectB.y + rectB.height) >= (rectA.y + rectA.height)) {
                
if ((rectB.x + rectB.width) > (rectA.x + rectA.width)) {
                    
t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
                    
if(t.width > 0 && t.height > 0) {
                        
a = t;
                        
rectCount++;
                    
}
                
} else {
                    
t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
                    
if(t.width > 0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}
                    
t.setBounds((rectB.x + rectB.width), rectB.y,
                                
(rectA.x + rectA.width) - (rectB.x + rectB.width),
                                
(rectA.y + rectA.height) - rectB.y);
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}
                
}
            
} else if (rectB.x <= rectA.x) {
                
if ((rectB.x + rectB.width) >= (rectA.x + rectA.width)) {
                    
t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
                    
if(t.width>0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
                                
(rectA.y + rectA.height) - (rectB.y + rectB.height));
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}
                
} else {
                    
t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
                    
if(t.width > 0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds((rectB.x + rectB.width), rectB.y,
                                
(rectA.x + rectA.width) - (rectB.x + rectB.width),
                                
rectB.height);
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
                                
(rectA.y + rectA.height) - (rectB.y + rectB.height));
                    
if(t.width > 0 && t.height > 0) {
                        
c = new Rectangle(t);
                        
rectCount++;
                    
}
                
}
            
} else if (rectB.x <= (rectA.x + rectA.width) && (rectB.x + rectB.width) > (rectA.x + rectA.width)) {
                
if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
                    
t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
                    
if(t.width > 0 && t.height > 0) {
                        
a = t;
                        
rectCount++;
                    
}
                
} else if (rectB.y <= rectA.y) {
                    
t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x,
                                
(rectB.y + rectB.height) - rectA.y);
                    
if(t.width > 0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
                                
(rectA.y + rectA.height) - (rectB.y + rectB.height));
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}
                
} else if ((rectB.y + rectB.height) > (rectA.y + rectA.height)) {
                    
t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
                    
if(t.width > 0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
                                
(rectA.y + rectA.height) - rectB.y);
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}
                
} else {
                    
t.setBounds(rectA.x, rectA.y, rectA.width, rectB.y - rectA.y);
                    
if(t.width > 0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds(rectA.x, rectB.y, rectB.x - rectA.x,
                                
rectB.height);
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds(rectA.x, (rectB.y + rectB.height), rectA.width,
                                
(rectA.y + rectA.height) - (rectB.y + rectB.height));
                    
if(t.width > 0 && t.height > 0) {
                        
c = new Rectangle(t);
                        
rectCount++;
                    
}
                
}
            
} else if (rectB.x >= rectA.x && (rectB.x + rectB.width) <= (rectA.x + rectA.width)) {
                
if (rectB.y <= rectA.y && (rectB.y + rectB.height) > (rectA.y + rectA.height)) {
                    
t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
                    
if(t.width > 0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}
                    
t.setBounds((rectB.x + rectB.width), rectA.y,
                                
(rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}
                
} else if (rectB.y <= rectA.y) {
                    
t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
                    
if(t.width > 0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds(rectB.x, (rectB.y + rectB.height),
                                
rectB.width,
                                
(rectA.y + rectA.height) - (rectB.y + rectB.height));
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds((rectB.x + rectB.width), rectA.y,
                                
(rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
                    
if(t.width > 0 && t.height > 0) {
                        
c = new Rectangle(t);
                        
rectCount++;
                    
}
                
} else {
                    
t.setBounds(rectA.x, rectA.y, rectB.x - rectA.x, rectA.height);
                    
if(t.width > 0 && t.height > 0) {
                        
a = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds(rectB.x, rectA.y, rectB.width,
                                
rectB.y - rectA.y);
                    
if(t.width > 0 && t.height > 0) {
                        
b = new Rectangle(t);
                        
rectCount++;
                    
}

                    
t.setBounds((rectB.x + rectB.width), rectA.y,
                                
(rectA.x + rectA.width) - (rectB.x + rectB.width), rectA.height);
                    
if(t.width > 0 && t.height > 0) {
                        
c = new Rectangle(t);
                        
rectCount++;
                    
}
                
}
            
}
        
}

        
result = new Rectangle[rectCount];
        
rectCount = 0;
        
if(a != null)
            
result[rectCount++] = a;
        
if(b != null)
            
result[rectCount++] = b;
        
if(c != null)
            
result[rectCount++] = c;
        
if(d != null)
            
result[rectCount++] = d;
        
return result;
    
}

    
/**
     
* Returns true if the mouse event specifies the left mouse button.
     
*
     
* @param anEvent
  
a MouseEvent object
     
* @return true if the left mouse button was active
     
*/

    
public static boolean isLeftMouseButton(MouseEvent anEvent) {
         
return ((anEvent.getModifiersEx() & InputEvent.BUTTON1_DOWN_MASK) != 0 ||
                 
anEvent.getButton() == MouseEvent.BUTTON1);
    
}

    
/**
     
* Returns true if the mouse event specifies the middle mouse button.
     
*
     
* @param anEvent
  
a MouseEvent object
     
* @return true if the middle mouse button was active
     
*/

    
public static boolean isMiddleMouseButton(MouseEvent anEvent) {
        
return ((anEvent.getModifiersEx() & InputEvent.BUTTON2_DOWN_MASK) != 0 ||
                
anEvent.getButton() == MouseEvent.BUTTON2);
    
}

    
/**
     
* Returns true if the mouse event specifies the right mouse button.
     
*
     
* @param anEvent
  
a MouseEvent object
     
* @return true if the right mouse button was active
     
*/

    
public static boolean isRightMouseButton(MouseEvent anEvent) {
        
return ((anEvent.getModifiersEx() & InputEvent.BUTTON3_DOWN_MASK) != 0 ||
                
anEvent.getButton() == MouseEvent.BUTTON3);
    
}

    
/**
     
* Compute the width of the string using a font with the specified
     
* "metrics" (sizes).
     
*
     
* @param fm
   
a FontMetrics object to compute with
     
* @param str
  
the String to compute
     
* @return an int containing the string width
     
*/

    
public static int computeStringWidth(FontMetrics fm,String str) {
        
// You can't assume that a string's width is the sum of its
        
// characters' widths in Java2D -- it may be smaller due to
        
// kerning, etc.
        
return SwingUtilities2.stringWidth(null, fm, str);
    
}

    
/**
     
* Compute and return the location of the icons origin, the
     
* location of origin of the text baseline, and a possibly clipped
     
* version of the compound labels string.
  
Locations are computed
     
* relative to the viewR rectangle.
     
* The JComponents orientation (LEADING/TRAILING) will also be taken
     
* into account and translated into LEFT/RIGHT values accordingly.
     
*/

    
public static String layoutCompoundLabel(JComponent c,
                                             
FontMetrics fm,
                                             
String text,
                                             
Icon icon,
                                             
int verticalAlignment,
                                             
int horizontalAlignment,
                                             
int verticalTextPosition,
                                             
int horizontalTextPosition,
                                             
Rectangle viewR,
                                             
Rectangle iconR,
                                             
Rectangle textR,
                                             
int textIconGap)
    
{
        
boolean orientationIsLeftToRight = true;
        
int
     
hAlign = horizontalAlignment;
        
int
     
hTextPos = horizontalTextPosition;

        
if (c != null) {
            
if (!(c.getComponentOrientation().isLeftToRight())) {
                
orientationIsLeftToRight = false;
            
}
        
}

        
// Translate LEADING/TRAILING values in horizontalAlignment
        
// to LEFT/RIGHT values depending on the components orientation
        
switch (horizontalAlignment) {
        
case LEADING:
            
hAlign = (orientationIsLeftToRight) ? LEFT : RIGHT;
            
break;
        
case TRAILING:
            
hAlign = (orientationIsLeftToRight) ? RIGHT : LEFT;
            
break;
        
}

        
// Translate LEADING/TRAILING values in horizontalTextPosition
        
// to LEFT/RIGHT values depending on the components orientation
        
switch (horizontalTextPosition) {
        
case LEADING:
            
hTextPos = (orientationIsLeftToRight) ? LEFT : RIGHT;
            
break;
        
case TRAILING:
            
hTextPos = (orientationIsLeftToRight) ? RIGHT : LEFT;
            
break;
        
}

        
return layoutCompoundLabelImpl(c,
                                       
fm,
                                       
text,
                                       
icon,
                                       
verticalAlignment,
                                       
hAlign,
                                       
verticalTextPosition,
                                       
hTextPos,
                                       
viewR,
                                       
iconR,
                                       
textR,
                                       
textIconGap);
    
}

    
/**
     
* Compute and return the location of the icons origin, the
     
* location of origin of the text baseline, and a possibly clipped
     
* version of the compound labels string.
  
Locations are computed
     
* relative to the viewR rectangle.
     
* This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
     
* values in horizontalTextPosition (they will default to RIGHT) and in
     
* horizontalAlignment (they will default to CENTER).
     
* Use the other version of layoutCompoundLabel() instead.
     
*/

    
public static String layoutCompoundLabel(
        
FontMetrics fm,
        
String text,
        
Icon icon,
        
int verticalAlignment,
        
int horizontalAlignment,
        
int verticalTextPosition,
        
int horizontalTextPosition,
        
Rectangle viewR,
        
Rectangle iconR,
        
Rectangle textR,
        
int textIconGap)
    
{
        
return layoutCompoundLabelImpl(null, fm, text, icon,
                                       
verticalAlignment,
                                       
horizontalAlignment,
                                       
verticalTextPosition,
                                       
horizontalTextPosition,
                                       
viewR, iconR, textR, textIconGap);
    
}

    
/**
     
* Compute and return the location of the icons origin, the
     
* location of origin of the text baseline, and a possibly clipped
     
* version of the compound labels string.
  
Locations are computed
     
* relative to the viewR rectangle.
     
* This layoutCompoundLabel() does not know how to handle LEADING/TRAILING
     
* values in horizontalTextPosition (they will default to RIGHT) and in
     
* horizontalAlignment (they will default to CENTER).
     
* Use the other version of layoutCompoundLabel() instead.
     
*/

    
private static String layoutCompoundLabelImpl(
        
JComponent c,
        
FontMetrics fm,
        
String text,
        
Icon icon,
        
int verticalAlignment,
        
int horizontalAlignment,
        
int verticalTextPosition,
        
int horizontalTextPosition,
        
Rectangle viewR,
        
Rectangle iconR,
        
Rectangle textR,
        
int textIconGap)
    
{
        
/* Initialize the icon bounds rectangle iconR.
         
*/

        
if (icon != null) {
            
iconR.width = icon.getIconWidth();
            
iconR.height = icon.getIconHeight();
        
}
        
else {
            
iconR.width = iconR.height = 0;
        
}

        
/* Initialize the text bounds rectangle textR.
  
If a null
         
* or and empty String was specified we substitute "" here
         
* and use 0,0,0,0 for textR.
         
*/


        
boolean textIsEmpty = (text == null) || text.equals("");
        
int lsb = 0;
        
int rsb = 0;
        
/* Unless both text and icon are non-null, we effectively ignore
         
* the value of textIconGap.
         
*/

        
int gap;

        
View v;
        
if (textIsEmpty) {
            
textR.width = textR.height = 0;
            
text = "";
            
gap = 0;
        
}
        
else {
            
int availTextWidth;
            
gap = (icon == null) ? 0 : textIconGap;

            
if (horizontalTextPosition == CENTER) {
                
availTextWidth = viewR.width;
            
}
            
else {
                
availTextWidth = viewR.width - (iconR.width + gap);
            
}
            
v = (c != null) ? (View) c.getClientProperty("html") : null;
            
if (v != null) {
                
textR.width = Math.min(availTextWidth,
                                       
(int) v.getPreferredSpan(View.X_AXIS));
                
textR.height = (int) v.getPreferredSpan(View.Y_AXIS);
            
} else {
                
textR.width = SwingUtilities2.stringWidth(c, fm, text);
                
lsb = SwingUtilities2.getLeftSideBearing(c, fm, text);
                
if (lsb < 0) {
                    
// If lsb is negative, add it to the width and later
                    
// adjust the x location. This gives more space than is
                    
// actually needed.
                    
// This is done like this for two reasons:
                    
// 1. If we set the width to the actual bounds all
                    
//
    
callers would have to account for negative lsb
                    
//
    
(pref size calculations ONLY look at width of
                    
//
    
textR)
                    
// 2. You can do a drawString at the returned location
                    
//
    
and the text won't be clipped.
                    
textR.width -= lsb;
                
}
                
if (textR.width > availTextWidth) {
                    
text = SwingUtilities2.clipString(c, fm,