/*
 
* 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 java.util.HashSet;
import java.util.Hashtable;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Locale;
import java.util.Vector;
import java.util.EventListener;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.VolatileImage;
import java.awt.Graphics2D;
import java.awt.peer.LightweightPeer;
import java.awt.dnd.DropTarget;
import java.awt.font.FontRenderContext;
import java.beans.PropertyChangeListener;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
import java.beans.Transient;

import java.applet.Applet;

import java.io.Serializable;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
import java.io.ObjectInputValidation;
import java.io.InvalidObjectException;
import java.util.concurrent.atomic.AtomicBoolean;

import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.plaf.*;
import static javax.swing.ClientPropertyKey.*;
import javax.accessibility.*;

import sun.awt.SunToolkit;
import sun.swing.SwingUtilities2;
import sun.swing.UIClientPropertyKey;

/**
 
* The base class for all Swing components except top-level containers.
 
* To use a component that inherits from <code>JComponent</code>,
 
* you must place the component in a containment hierarchy
 
* whose root is a top-level Swing container.
 
* Top-level Swing containers --
 
* such as <code>JFrame</code>, <code>JDialog</code>,
 
* and <code>JApplet</code> --
 
* are specialized components
 
* that provide a place for other Swing components to paint themselves.
 
* For an explanation of containment hierarchies, see
 
* <a
 
href=" https://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html">Swing
 
Components and the Containment Hierarchy</a>,
 
* a section in <em>The Java Tutorial</em>.
 
*
 
* <p>
 
* The <code>JComponent</code> class provides:
 
* <ul>
 
* <li>The base class for both standard and custom components
 
*
     
that use the Swing architecture.
 
* <li>A "pluggable look and feel" (L&amp;F) that can be specified by the
 
*
     
programmer or (optionally) selected by the user at runtime.
 
*
     
The look and feel for each component is provided by a
 
*
     
<em>UI delegate</em> -- an object that descends from
 
*
     
.
 
*
     
See <a
 
* href=" https://docs.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html">How
 
*
     
to Set the Look and Feel</a>
 
*
     
in <em>The Java Tutorial</em>
 
*
     
for more information.
 
* <li>Comprehensive keystroke handling.
 
*
     
See the document <a
 
* href=" https://docs.oracle.com/javase/tutorial/uiswing/misc/keybinding.html">How
 
to Use Key Bindings</a>,
 
*
     
an article in <em>The Java Tutorial</em>,
 
*
     
for more information.
 
* <li>Support for tool tips --
 
*
     
short descriptions that pop up when the cursor lingers
 
*
     
over a component.
 
*
     
See <a
 
* href=" https://docs.oracle.com/javase/tutorial/uiswing/components/tooltip.html">How
 
*
     
to Use Tool Tips</a>
 
*
     
in <em>The Java Tutorial</em>
 
*
     
for more information.
 
* <li>Support for accessibility.
 
*
     
<code>JComponent</code> contains all of the methods in the
 
*
     
<code>Accessible</code> interface,
 
*
     
but it doesn't actually implement the interface.
  
That is the
 
*
     
responsibility of the individual classes
 
*
     
that extend <code>JComponent</code>.
 
* <li>Support for component-specific properties.
 
*
     
With the {@link #putClientProperty}
 
*
     
and {@link #getClientProperty} methods,
 
*
     
you can associate name-object pairs
 
*
     
with any object that descends from <code>JComponent</code>.
 
* <li>An infrastructure for painting
 
*
     
that includes double buffering and support for borders.
 
*
     
For more information see <a
 
* href=" http://www.oracle.com/technetwork/java/painting-140037.html#swing">Painting</a>
 
and
 
* <a href=" https://docs.oracle.com/javase/tutorial/uiswing/components/border.htmll">How
 
*
     
to Use Borders</a>,
 
*
     
both of which are sections in <em>The Java Tutorial</em>.
 
* </ul>
 
* For more information on these subjects, see the
 
*<a href="package-summary.html#package_description">Swing package description</a>
 
* and <em>The Java Tutorial</em> section
 
*<a href="https://docs.oracle.com/javase/tutorial/uiswing/components/jcomponent.html">The JComponent Class</a>.
 
* <p>
 
* <code>JComponent</code> and its subclasses document default values
 
* for certain properties.
  
For example, <code>JTable</code> documents the
 
* default row height as 16.
  
Each <code>JComponent</code> subclass
 
* that has a <code>ComponentUI</code> will create the
 
* <code>ComponentUI</code> as part of its constructor.
  
In order
 
* to provide a particular look and feel each
 
* <code>ComponentUI</code> may set properties back on the
 
* <code>JComponent</code> that created it.
  
For example, a custom
 
* look and feel may require <code>JTable</code>s to have a row
 
* height of 24. The documented defaults are the value of a property
 
* BEFORE the <code>ComponentUI</code> has been installed.
  
If you
 
* need a specific value for a particular property you should
 
* explicitly set it.
 
* <p>
 
* In release 1.4, the focus subsystem was rearchitected.
 
* For more information, see
 
* <a href=" https://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html">
 
* How to Use the Focus Subsystem</a>,
 
* a section in <em>The Java Tutorial</em>.
 
* <p>
 
* <strong>Warning:</strong> Swing is not thread safe. For more
 
* information see <a
 
* href="package-summary.html#threading">Swing's Threading
 
* Policy</a>.
 
* <p>
 
* <strong>Warning:</strong>
 
* Serialized objects of this class will not be compatible with
 
* future Swing releases. The current serialization support is
 
* appropriate for short term storage or RMI between applications running
 
* the same version of Swing.
  
As of 1.4, support for long term storage
 
* of all JavaBeans&trade;
 
* has been added to the <code>java.beans</code> package.
 
* Please see .
 
*
 
* @see KeyStroke
 
* @see Action
 
* @see #setBorder
 
* @see #registerKeyboardAction
 
* @see JOptionPane
 
* @see #setDebugGraphicsOptions
 
* @see #setToolTipText
 
* @see #setAutoscrolls
 
*
 
* @author Hans Muller
 
* @author Arnaud Weber
 
*/

public abstract class JComponent extends Container implements Serializable,
                                              
TransferHandler.HasGetTransferHandler
{
    
/**
     
* @see #getUIClassID
     
* @see #writeObject
     
*/
    
private static final String uiClassID = "ComponentUI";

    
/**
     
* @see #readObject
     
*/
    
private static final Hashtable<ObjectInputStream, ReadObjectCallback> readObjectCallbacks =
            
new Hashtable<ObjectInputStream, ReadObjectCallback>(1);

    
/**
     
* Keys to use for forward focus traversal when the JComponent is
     
* managing focus.
     
*/

    
private static Set<KeyStroke> managingFocusForwardTraversalKeys;

    
/**
     
* Keys to use for backward focus traversal when the JComponent is
     
* managing focus.
     
*/

    
private static Set<KeyStroke> managingFocusBackwardTraversalKeys;

    
// Following are the possible return values from getObscuredState.
    
private static final int NOT_OBSCURED = 0;
    
private static final int PARTIALLY_OBSCURED = 1;
    
private static final int COMPLETELY_OBSCURED = 2;

    
/**
     
* Set to true when DebugGraphics has been loaded.
     
*/
    
static boolean DEBUG_GRAPHICS_LOADED;

    
/**
     
* Key used to look up a value from the AppContext to determine the
     
* JComponent the InputVerifier is running for. That is, if
     
* AppContext.get(INPUT_VERIFIER_SOURCE_KEY) returns non-null, it
     
* indicates the EDT is calling into the InputVerifier from the
     
* returned component.
     
*/

    
private static final Object INPUT_VERIFIER_SOURCE_KEY =
            
new StringBuilder("InputVerifierSourceKey");

    
/* The following fields support set methods for the corresponding
     
* java.awt.Component properties.
     
*/

    
private boolean isAlignmentXSet;
    
private float alignmentX;
    
private boolean isAlignmentYSet;
    
private float alignmentY;

    
/**
     
* Backing store for JComponent properties and listeners
     
*/


    
/** The look and feel delegate for this component. */
    
protected transient ComponentUI ui;
    
/** A list of event listeners for this component. */
    
protected EventListenerList listenerList = new EventListenerList();

    
private transient ArrayTable clientProperties;
    
private VetoableChangeSupport vetoableChangeSupport;
    
/**
     
* Whether or not autoscroll has been enabled.
     
*/
    
private boolean autoscrolls;
    
private Border border;
    
private int flags;

    
/* Input verifier for this component */
    
private InputVerifier inputVerifier = null;

    
private boolean verifyInputWhenFocusTarget = true;

    
/**
     
* Set in <code>_paintImmediately</code>.
     
* Will indicate the child that initiated the painting operation.
     
* If <code>paintingChild</code> is opaque, no need to paint
     
* any child components after <code>paintingChild</code>.
     
* Test used in <code>paintChildren</code>.
     
*/

    
transient Component
         
paintingChild
;

    
/**
     
* Constant used for <code>registerKeyboardAction</code> that
     
* means that the command should be invoked when
     
* the component has the focus.
     
*/

    
public static final int WHEN_FOCUSED = 0;

    
/**
     
* Constant used for <code>registerKeyboardAction</code> that
     
* means that the command should be invoked when the receiving
     
* component is an ancestor of the focused component or is
     
* itself the focused component.
     
*/

    
public static final int WHEN_ANCESTOR_OF_FOCUSED_COMPONENT = 1;

    
/**
     
* Constant used for <code>registerKeyboardAction</code> that
     
* means that the command should be invoked when
     
* the receiving component is in the window that has the focus
     
* or is itself the focused component.
     
*/

    
public static final int WHEN_IN_FOCUSED_WINDOW = 2;

    
/**
     
* Constant used by some of the APIs to mean that no condition is defined.
     
*/
    
public static final int UNDEFINED_CONDITION = -1;

    
/**
     
* The key used by <code>JComponent</code> to access keyboard bindings.
     
*/
    
private static final String KEYBOARD_BINDINGS_KEY = "_KeyboardBindings";

    
/**
     
* An array of <code>KeyStroke</code>s used for
     
* <code>WHEN_IN_FOCUSED_WINDOW</code> are stashed
     
* in the client properties under this string.
     
*/

    
private static final String WHEN_IN_FOCUSED_WINDOW_BINDINGS = "_WhenInFocusedWindow";

    
/**
     
* The comment to display when the cursor is over the component,
     
* also known as a "value tip", "flyover help", or "flyover label".
     
*/

    
public static final String TOOL_TIP_TEXT_KEY = "ToolTipText";

    
private static final String NEXT_FOCUS = "nextFocus";

    
/**
     
* <code>JPopupMenu</code> assigned to this component
     
* and all of its children
     
*/
    
private JPopupMenu popupMenu;

    
/** Private flags **/
    
private static final int IS_DOUBLE_BUFFERED
                       
=
  
0;
    
private static final int ANCESTOR_USING_BUFFER
                    
=
  
1;
    
private static final int IS_PAINTING_TILE
                         
=
  
2;
    
private static final int IS_OPAQUE
                                
=
  
3;
    
private static final int KEY_EVENTS_ENABLED
                       
=
  
4;
    
private static final int FOCUS_INPUTMAP_CREATED
                   
=
  
5;
    
private static final int ANCESTOR_INPUTMAP_CREATED
                
=
  
6;
    
private static final int WIF_INPUTMAP_CREATED
                     
=
  
7;
    
private static final int ACTIONMAP_CREATED
                        
=
  
8;
    
private static final int CREATED_DOUBLE_BUFFER
                    
=
  
9;
    
// bit 10 is free
    
private static final int IS_PRINTING
                              
= 11;
    
private static final int IS_PRINTING_ALL
                          
= 12;
    
private static final int IS_REPAINTING
                            
= 13;
    
/** Bits 14-21 are used to handle nested writeObject calls. **/
    
private static final int WRITE_OBJ_COUNTER_FIRST
                  
= 14;
    
private static final int RESERVED_1
                               
= 15;
    
private static final int RESERVED_2
                               
= 16;
    
private static final int RESERVED_3
                               
= 17;
    
private static final int RESERVED_4
                               
= 18;
    
private static final int RESERVED_5
                               
= 19;
    
private static final int RESERVED_6
                               
= 20;
    
private static final int WRITE_OBJ_COUNTER_LAST
                   
= 21;

    
private static final int REQUEST_FOCUS_DISABLED
                   
= 22;
    
private static final int INHERITS_POPUP_MENU
                      
= 23;
    
private static final int OPAQUE_SET
                               
= 24;
    
private static final int AUTOSCROLLS_SET
                          
= 25;
    
private static final int FOCUS_TRAVERSAL_KEYS_FORWARD_SET
         
= 26;
    
private static final int FOCUS_TRAVERSAL_KEYS_BACKWARD_SET
        
= 27;

    
private transient AtomicBoolean revalidateRunnableScheduled = new AtomicBoolean(false);

    
/**
     
* Temporary rectangles.
     
*/
    
private static java.util.List<Rectangle> tempRectangles = new java.util.ArrayList<Rectangle>(11);

    
/** Used for <code>WHEN_FOCUSED</code> bindings. */
    
private InputMap focusInputMap;
    
/** Used for <code>WHEN_ANCESTOR_OF_FOCUSED_COMPONENT</code> bindings. */
    
private InputMap ancestorInputMap;
    
/** Used for <code>WHEN_IN_FOCUSED_KEY</code> bindings. */
    
private ComponentInputMap windowInputMap;

    
/** ActionMap. */
    
private ActionMap actionMap;

    
/** Key used to store the default locale in an AppContext **/
    
private static final String defaultLocale = "JComponent.defaultLocale";

    
private static Component componentObtainingGraphicsFrom;
    
private static Object componentObtainingGraphicsFromLock = new
            
StringBuilder("componentObtainingGraphicsFrom");

    
/**
     
* AA text hints.
     
*/
    
transient private Object aaTextInfo;

    
static Graphics safelyGetGraphics(Component c) {
        
return safelyGetGraphics(c, SwingUtilities.getRoot(c));
    
}

    
static Graphics safelyGetGraphics(Component c, Component root) {
        
synchronized(componentObtainingGraphicsFromLock) {
            
componentObtainingGraphicsFrom = root;
            
Graphics g = c.getGraphics();
            
componentObtainingGraphicsFrom = null;
            
return g;
        
}
    
}

    
static void getGraphicsInvoked(Component root) {
        
if (!JComponent.isComponentObtainingGraphicsFrom(root)) {
            
JRootPane rootPane = ((RootPaneContainer)root).getRootPane();
            
if (rootPane != null) {
                
rootPane.disableTrueDoubleBuffering();
            
}
        
}
    
}


    
/**
     
* Returns true if {@code c} is the component the graphics is being
     
* requested of. This is intended for use when getGraphics is invoked.
     
*/

    
private static boolean isComponentObtainingGraphicsFrom(Component c) {
        
synchronized(componentObtainingGraphicsFromLock) {
            
return (componentObtainingGraphicsFrom == c);
        
}
    
}

    
/**
     
* Returns the Set of <code>KeyStroke</code>s to use if the component
     
* is managing focus for forward focus traversal.
     
*/

    
static Set<KeyStroke> getManagingFocusForwardTraversalKeys() {
        
synchronized(JComponent.class) {
            
if (managingFocusForwardTraversalKeys == null) {
                
managingFocusForwardTraversalKeys = new HashSet<KeyStroke>(1);
                
managingFocusForwardTraversalKeys.add(
                    
KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
                                           
InputEvent.CTRL_MASK));
            
}
        
}
        
return managingFocusForwardTraversalKeys;
    
}

    
/**
     
* Returns the Set of <code>KeyStroke</code>s to use if the component
     
* is managing focus for backward focus traversal.
     
*/

    
static Set<KeyStroke> getManagingFocusBackwardTraversalKeys() {
        
synchronized(JComponent.class) {
            
if (managingFocusBackwardTraversalKeys == null) {
                
managingFocusBackwardTraversalKeys = new HashSet<KeyStroke>(1);
                
managingFocusBackwardTraversalKeys.add(
                    
KeyStroke.getKeyStroke(KeyEvent.VK_TAB,
                                           
InputEvent.SHIFT_MASK |
                                           
InputEvent.CTRL_MASK));
            
}
        
}
        
return managingFocusBackwardTraversalKeys;
    
}

    
private static Rectangle fetchRectangle() {
        
synchronized(tempRectangles) {
            
Rectangle rect;
            
int size = tempRectangles.size();
            
if (size > 0) {
                
rect = tempRectangles.remove(size - 1);
            
}
            
else {
                
rect = new Rectangle(0, 0, 0, 0);
            
}
            
return rect;
        
}
    
}

    
private static void recycleRectangle(Rectangle rect) {
        
synchronized(tempRectangles) {
            
tempRectangles.add(rect);
        
}
    
}

    
/**
     
* Sets whether or not <code>getComponentPopupMenu</code> should delegate
     
* to the parent if this component does not have a <code>JPopupMenu</code>
     
* assigned to it.
     
* <p>
     
* The default value for this is false, but some <code>JComponent</code>
     
* subclasses that are implemented as a number of <code>JComponent</code>s
     
* may set this to true.
     
* <p>
     
* This is a bound property.
     
*
     
* @param value whether or not the JPopupMenu is inherited
     
* @see #setComponentPopupMenu
     
* @beaninfo
     
*
        
bound: true
     
*
  
description: Whether or not the JPopupMenu is inherited
     
* @since 1.5
     
*/

    
public void setInheritsPopupMenu(boolean value) {
        
boolean oldValue = getFlag(INHERITS_POPUP_MENU);
        
setFlag(INHERITS_POPUP_MENU, value);
        
firePropertyChange("inheritsPopupMenu", oldValue, value);
    
}

    
/**
     
* Returns true if the JPopupMenu should be inherited from the parent.
     
*
     
* @see #setComponentPopupMenu
     
* @since 1.5
     
*/

    
public boolean getInheritsPopupMenu() {
        
return getFlag(INHERITS_POPUP_MENU);
    
}

    
/**
     
* Sets the <code>JPopupMenu</code> for this <code>JComponent</code>.
     
* The UI is responsible for registering bindings and adding the necessary
     
* listeners such that the <code>JPopupMenu</code> will be shown at
     
* the appropriate time. When the <code>JPopupMenu</code> is shown
     
* depends upon the look and feel: some may show it on a mouse event,
     
* some may enable a key binding.
     
* <p>
     
* If <code>popup</code> is null, and <code>getInheritsPopupMenu</code>
     
* returns true, then <code>getComponentPopupMenu</code> will be delegated
     
* to the parent. This provides for a way to make all child components
     
* inherit the popupmenu of the parent.
     
* <p>
     
* This is a bound property.
     
*
     
* @param popup - the popup that will be assigned to this component
     
*
                
may be null
     
* @see #getComponentPopupMenu
     
* @beaninfo
     
*
        
bound: true
     
*
    
preferred: true
     
*
  
description: Popup to show
     
* @since 1.5
     
*/

    
public void setComponentPopupMenu(JPopupMenu popup) {
        
if(popup != null) {
            
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
        
}
        
JPopupMenu oldPopup = this.popupMenu;
        
this.popupMenu = popup;
        
firePropertyChange("componentPopupMenu", oldPopup, popup);
    
}

    
/**
     
* Returns <code>JPopupMenu</code> that assigned for this component.
     
* If this component does not have a <code>JPopupMenu</code> assigned
     
* to it and <code>getInheritsPopupMenu</code> is true, this
     
* will return <code>getParent().getComponentPopupMenu()</code> (assuming
     
* the parent is valid.)
     
*
     
* @return <code>JPopupMenu</code> assigned for this component
     
*
         
or <code>null</code> if no popup assigned
     
* @see #setComponentPopupMenu
     
* @since 1.5
     
*/

    
public JPopupMenu getComponentPopupMenu() {

        
if(!getInheritsPopupMenu()) {
            
return popupMenu;
        
}

        
if(popupMenu == null) {
            
// Search parents for its popup
            
Container parent = getParent();
            
while (parent != null) {
                
if(parent instanceof JComponent) {
                    
return ((JComponent)parent).getComponentPopupMenu();
                
}
                
if(parent instanceof Window ||
                   
parent instanceof Applet) {
                    
// Reached toplevel, break and return null
                    
break;
                
}
                
parent = parent.getParent();
            
}
            
return null;
        
}

        
return popupMenu;
    
}

    
/**
     
* Default <code>JComponent</code> constructor.
  
This constructor does
     
* very little initialization beyond calling the <code>Container</code>
     
* constructor.
  
For example, the initial layout manager is
     
* <code>null</code>. It does, however, set the component's locale
     
* property to the value returned by
     
* <code>JComponent.getDefaultLocale</code>.
     
*
     
* @see #getDefaultLocale
     
*/

    
public JComponent() {
        
super();
        
// We enable key events on all JComponents so that accessibility
        
// bindings will work everywhere. This is a partial fix to BugID
        
// 4282211.
        
enableEvents(AWTEvent.KEY_EVENT_MASK);
        
if (isManagingFocus()) {
            
LookAndFeel.installProperty(this,
                                        
"focusTraversalKeysForward",
                                  
getManagingFocusForwardTraversalKeys());
            
LookAndFeel.installProperty(this,
                                        
"focusTraversalKeysBackward",
                                  
getManagingFocusBackwardTraversalKeys());
        
}

        
super.setLocale( JComponent.getDefaultLocale() );
    
}


    
/**
     
* Resets the UI property to a value from the current look and feel.
     
* <code>JComponent</code> subclasses must override this method
     
* like this:
     
* <pre>
     
*
   
public void updateUI() {
     
*
      
setUI((SliderUI)UIManager.getUI(this);
     
*
   
}
     
*
  
</pre>
     
*
     
* @see #setUI
     
* @see UIManager#getLookAndFeel
     
* @see UIManager#getUI
     
*/

    
public void updateUI() {}


    
/**
     
* Sets the look and feel delegate for this component.
     
* <code>JComponent</code> subclasses generally override this method
     
* to narrow the argument type. For example, in <code>JSlider</code>:
     
* <pre>
     
* public void setUI(SliderUI newUI) {
     
*super.setUI(newUI);
     
* }
     
*
  
</pre>
     
* <p>
     
* Additionally <code>JComponent</code> subclasses must provide a
     
* <code>getUI</code> method that returns the correct type.
  
For example:
     
* <pre>
     
* public SliderUI getUI() {
     
*return (SliderUI)ui;
     
* }
     
* </pre>
     
*
     
* @param newUI the new UI delegate
     
* @see #updateUI
     
* @see UIManager#getLookAndFeel
     
* @see UIManager#getUI
     
* @beaninfo
     
*
        
bound: true
     
*
       
hidden: true
     
*
    
attribute: visualUpdate true
     
*
  
description: The component's look and feel delegate.
     
*/

    
protected void setUI(ComponentUI newUI) {
        
/* We do not check that the UI instance is different
         
* before allowing the switch in order to enable the
         
* same UI instance *with different default settings*
         
* to be installed.
         
*/


        
uninstallUIAndProperties();

        
// aaText shouldn't persist between look and feels, reset it.
        
aaTextInfo =
            
UIManager.getDefaults().get(SwingUtilities2.AA_TEXT_PROPERTY_KEY);
        
ComponentUI oldUI = ui;
        
ui = newUI;
        
if (ui != null) {
            
ui.installUI(this);
        
}

        
firePropertyChange("UI", oldUI, newUI);
        
revalidate();
        
repaint();
    
}

    
/**
     
* Uninstalls the UI, if any, and any client properties designated
     
* as being specific to the installed UI - instances of
     
* {@code UIClientPropertyKey}.
     
*/

    
private void uninstallUIAndProperties() {
        
if (ui != null) {
            
ui.uninstallUI(this);
            
//clean UIClientPropertyKeys from client properties
            
if (clientProperties != null) {
                
synchronized(clientProperties) {
                    
Object[] clientPropertyKeys =
                        
clientProperties.getKeys(null);
                    
if (clientPropertyKeys != null) {
                        
for (Object key : clientPropertyKeys) {
                            
if (key instanceof UIClientPropertyKey) {
                                
putClientProperty(key, null);
                            
}
                        
}
                    
}
                
}
            
}
        
}
    
}

    
/**
     
* Returns the <code>UIDefaults</code> key used to
     
* look up the name of the <code>swing.plaf.ComponentUI</code>
     
* class that defines the look and feel
     
* for this component.
  
Most applications will never need to
     
* call this method.
  
Subclasses of <code>JComponent</code> that support
     
* pluggable look and feel should override this method to
     
* return a <code>UIDefaults</code> key that maps to the
     
* <code>ComponentUI</code> subclass that defines their look and feel.
     
*
     
* @return the <code>UIDefaults</code> key for a
     
*
          
<code>ComponentUI</code> subclass
     
* @see UIDefaults#getUI
     
* @beaninfo
     
*
      
expert: true
     
* description: UIClassID
     
*/

    
public String getUIClassID() {
        
return uiClassID;
    
}


    
/**
     
* Returns the graphics object used to paint this component.
     
* If <code>DebugGraphics</code> is turned on we create a new
     
* <code>DebugGraphics</code> object if necessary.
     
* Otherwise we just configure the
     
* specified graphics object's foreground and font.
     
*
     
* @param g the original <code>Graphics</code> object
     
* @return a <code>Graphics</code> object configured for this component
     
*/

    
protected Graphics getComponentGraphics(Graphics g) {
        
Graphics componentGraphics = g;
        
if (ui != null && DEBUG_GRAPHICS_LOADED) {
            
if ((DebugGraphics.debugComponentCount() != 0) &&
                    
(shouldDebugGraphics() != 0) &&
                    
!(g instanceof DebugGraphics)) {
                
componentGraphics = new DebugGraphics(g,this);
            
}
        
}
        
componentGraphics.setColor(getForeground());
        
componentGraphics.setFont(getFont());

        
return componentGraphics;
    
}


    
/**
     
* Calls the UI delegate's paint method, if the UI delegate
     
* is non-<code>null</code>.
  
We pass the delegate a copy of the
     
* <code>Graphics</code> object to protect the rest of the
     
* paint code from irrevocable changes
     
* (for example, <code>Graphics.translate</code>).
     
* <p>
     
* If you override this in a subclass you should not make permanent
     
* changes to the passed in <code>Graphics</code>. For example, you
     
* should not alter the clip <code>Rectangle</code> or modify the
     
* transform. If you need to do these operations you may find it
     
* easier to create a new <code>Graphics</code> from the passed in
     
* <code>Graphics</code> and manipulate it. Further, if you do not
     
* invoker super's implementation you must honor the opaque property,
     
* that is
     
* if this component is opaque, you must completely fill in the background
     
* in a non-opaque color. If you do not honor the opaque property you
     
* will likely see visual artifacts.
     
* <p>
     
* The passed in <code>Graphics</code> object might
     
* have a transform other than the identify transform
     
* installed on it.
  
In this case, you might get
     
* unexpected results if you cumulatively apply
     
* another transform.
     
*
     
* @param g the <code>Graphics</code> object to protect
     
* @see #paint
     
* @see ComponentUI
     
*/

    
protected void paintComponent(Graphics g) {
        
if (ui != null) {
            
Graphics scratchGraphics = (g == null) ? null : g.create();
            
try {
                
ui.update(scratchGraphics, this);
            
}
            
finally {
                
scratchGraphics.dispose();
            
}
        
}
    
}

    
/**
     
* Paints this component's children.
     
* If <code>shouldUseBuffer</code> is true,
     
* no component ancestor has a buffer and
     
* the component children can use a buffer if they have one.
     
* Otherwise, one ancestor has a buffer currently in use and children
     
* should not use a buffer to paint.
     
* @param g
  
the <code>Graphics</code> context in which to paint
     
* @see #paint
     
* @see java.awt.Container#paint
     
*/

    
protected void paintChildren(Graphics g) {
        
Graphics sg = g;

        
synchronized(getTreeLock()) {
            
int i = getComponentCount() - 1;
            
if (i < 0) {
                
return;
            
}
            
// If we are only to paint to a specific child, determine
            
// its index.
            
if (paintingChild != null &&
                
(paintingChild instanceof JComponent) &&
                
paintingChild.isOpaque()) {
                
for (; i >= 0; i--) {
                    
if (getComponent(i) == paintingChild){
                        
break;
                    
}
                
}
            
}
            
Rectangle tmpRect = fetchRectangle();
            
boolean checkSiblings = (!isOptimizedDrawingEnabled() &&
                                     
checkIfChildObscuredBySibling());
            
Rectangle clipBounds = null;
            
if (checkSiblings) {
                
clipBounds = sg.getClipBounds();
                
if (clipBounds == null) {
                    
clipBounds = new Rectangle(0, 0, getWidth(),
                                               
getHeight());
                
}
            
}
            
boolean printing = getFlag(IS_PRINTING);
            
final Window window = SwingUtilities.getWindowAncestor(this);
            
final boolean isWindowOpaque = window == null || window.isOpaque();
            
for (; i >= 0 ; i--) {
                
Component comp = getComponent(i);
                
if (comp == null) {
                    
continue;
                
}

                
final boolean isJComponent = comp instanceof JComponent;

                
// Enable painting of heavyweights in non-opaque windows.
                
// See 6884960
                
if ((!isWindowOpaque || isJComponent ||
                            
isLightweightComponent(comp)) && comp.isVisible())
                
{
                    
Rectangle cr;

                    
cr = comp.getBounds(tmpRect);

                    
boolean hitClip = g.hitClip(cr.x, cr.y, cr.width,
                                                
cr.height);

                    
if (hitClip) {
                        
if (checkSiblings && i > 0) {
                            
int x = cr.x;
                            
int y = cr.y;
                            
int width = cr.width;
                            
int height = cr.height;
                            
SwingUtilities.computeIntersection
                                
(clipBounds.x, clipBounds.y,
                                 
clipBounds.width, clipBounds.height, cr);

                            
if(getObscuredState(i, cr.x, cr.y, cr.width,
                                          
cr.height) == COMPLETELY_OBSCURED) {
                                
continue;
                            
}
                            
cr.x = x;
                            
cr.y = y;
                            
cr.width = width;
                            
cr.height = height;
                        
}
                        
Graphics cg = sg.create(cr.x, cr.y, cr.width,
                                                
cr.height);
                        
cg.setColor(comp.getForeground());
                        
cg.setFont(comp.getFont());
                        
boolean shouldSetFlagBack = false;
                        
try {
                            
if(isJComponent) {
                                
if(getFlag(ANCESTOR_USING_BUFFER)) {
                                    
((JComponent)comp).setFlag(
                                                 
ANCESTOR_USING_BUFFER,true);
                                    
shouldSetFlagBack = true;
                                
}
                                
if(getFlag(IS_PAINTING_TILE)) {
                                    
((JComponent)comp).setFlag(
                                                 
IS_PAINTING_TILE,true);
                                    
shouldSetFlagBack = true;
                                
}
                                
if(!printing) {
                                    
comp.paint(cg);
                                
}
                                
else {
                                    
if (!getFlag(IS_PRINTING_ALL)) {
                                        
comp.print(cg);
                                    
}
                                    
else {
                                        
comp.printAll(cg);
                                    
}
                                
}
                            
} else {
                                
// The component is either lightweight, or
                                
// heavyweight in a non-opaque window
                                
if (!printing) {
                                    
comp.paint(cg);
                                
}
                                
else {
                                    
if (!getFlag(IS_PRINTING_ALL)) {
                                        
comp.print(cg);
                                    
}
                                    
else {
                                        
comp.printAll(cg);
                                    
}
                                
}
                            
}
                        
} finally {
                            
cg.dispose();
                            
if(shouldSetFlagBack) {
                                
((JComponent)comp).setFlag(
                                             
ANCESTOR_USING_BUFFER,false);
                                
((JComponent)comp).setFlag(
                                             
IS_PAINTING_TILE,false);
                            
}
                        
}
                    
}
                
}

            
}
            
recycleRectangle(tmpRect);
        
}
    
}

    
/**
     
* Paints the component's border.
     
* <p>
     
* If you override this in a subclass you should not make permanent
     
* changes to the passed in <code>Graphics</code>. For example, you
     
* should not alter the clip <code>Rectangle</code> or modify the
     
* transform. If you need to do these operations you may find it
     
* easier to create a new <code>Graphics</code> from the passed in
     
* <code>Graphics</code> and manipulate it.
     
*
     
* @param g
  
the <code>Graphics</code> context in which to paint
     
*
     
* @see #paint
     
* @see #setBorder
     
*/

    
protected void paintBorder(Graphics g) {
        
Border border = getBorder();
        
if (border != null) {
            
border.paintBorder(this, g, 0, 0, getWidth(), getHeight());
        
}
    
}


    
/**
     
* Calls <code>paint</code>.
  
Doesn't clear the background but see
     
* <code>ComponentUI.update</code>, which is called by
     
* <code>paintComponent</code>.
     
*
     
* @param g the <code>Graphics</code> context in which to paint
     
* @see #paint
     
* @see #paintComponent
     
*
 

     
*/

    
public void update(Graphics g) {
        
paint(g);
    
}


    
/**
     
* Invoked by Swing to draw components.
     
* Applications should not invoke <code>paint</code> directly,
     
* but should instead use the <code>repaint</code> method to
     
* schedule the component for redrawing.
     
* <p>
     
* This method actually delegates the work of painting to three
     
* protected methods: <code>paintComponent</code>,
     
* <code>paintBorder</code>,
     
* and <code>paintChildren</code>.
  
They're called in the order
     
* listed to ensure that children appear on top of component itself.
     
* Generally speaking, the component and its children should not
     
* paint in the insets area allocated to the border. Subclasses can
     
* just override this method, as always.
  
A subclass that just
     
* wants to specialize the UI (look and feel) delegate's
     
* <code>paint</code> method should just override
     
* <code>paintComponent</code>.
     
*
     
* @param g
  
the <code>Graphics</code> context in which to paint
     
* @see #paintComponent
     
* @see #paintBorder
     
* @see #paintChildren
     
* @see #getComponentGraphics
     
* @see #repaint
     
*/

    
public void paint(Graphics g) {
        
boolean shouldClearPaintFlags = false;

        
if ((getWidth() <= 0) || (getHeight() <= 0)) {
            
return;
        
}

        
Graphics componentGraphics = getComponentGraphics(g);
        
Graphics co = componentGraphics.create();
        
try {
            
RepaintManager repaintManager = RepaintManager.currentManager(this);
            
Rectangle clipRect = co.getClipBounds();
            
int clipX;
            
int clipY;
            
int clipW;
            
int clipH;
            
if (clipRect == null) {
                
clipX = clipY = 0;
                
clipW = getWidth();
                
clipH = getHeight();
            
}
            
else {
                
clipX = clipRect.x;
                
clipY = clipRect.y;
                
clipW = clipRect.width;
                
clipH = clipRect.height;
            
}

            
if(clipW > getWidth()) {
                
clipW = getWidth();
            
}
            
if(clipH > getHeight()) {
                
clipH = getHeight();
            
}

            
if(getParent() != null && !(getParent() instanceof JComponent)) {
                
adjustPaintFlags();
                
shouldClearPaintFlags = true;
            
}

            
int bw,bh;
            
boolean printing = getFlag(IS_PRINTING);
            
if (!printing && repaintManager.isDoubleBufferingEnabled() &&
                
!getFlag(ANCESTOR_USING_BUFFER) && isDoubleBuffered() &&
                
(getFlag(IS_REPAINTING) || repaintManager.isPainting()))
            
{
                
repaintManager.beginPaint();
                
try {
                    
repaintManager.paint(this, this, co, clipX, clipY, clipW,
                                         
clipH);
                
} finally {
                    
repaintManager.endPaint();
                
}
            
}
            
else {
                
// Will ocassionaly happen in 1.2, especially when printing.
                
if (clipRect == null) {
                    
co.setClip(clipX, clipY, clipW, clipH);
                
}

                
if (!rectangleIsObscured(clipX,clipY,clipW,clipH)) {
                    
if (!printing) {
                        
paintComponent(co);
                        
paintBorder(co);
                    
}
                    
else {
                        
printComponent(co);
                        
printBorder(co);
                    
}
                
}
                
if (!printing) {
                    
paintChildren(co);
                
}
                
else {
                    
printChildren(co);
                
}
            
}
        
} finally {
            
co.dispose();
            
if(shouldClearPaintFlags) {
                
setFlag(ANCESTOR_USING_BUFFER,false);
                
setFlag(IS_PAINTING_TILE,false);
                
setFlag(IS_PRINTING,false);
                
setFlag(IS_PRINTING_ALL,false);
            
}
        
}
    
}

    
// paint forcing use of the double buffer.
  
This is used for historical

    
// reasons: JViewport, when scrolling, previously directly invoked paint
    
// while turning off double buffering at the RepaintManager level, this
    
// codes simulates that.
    
void paintForceDoubleBuffered(Graphics g) {
        
RepaintManager rm = RepaintManager.currentManager(this);
        
Rectangle clip = g.getClipBounds();
        
rm.beginPaint();
        
setFlag(IS_REPAINTING, true);
        
try {
            
rm.paint(this, this, g, clip.x, clip.y, clip.width, clip.height);
        
} finally {
            
rm.endPaint();
            
setFlag(IS_REPAINTING, false);
        
}
    
}

    
/**
     
* Returns true if this component, or any of its ancestors, are in
     
* the processing of painting.
     
*/

    
boolean isPainting() {
        
Container component = this;
        
while (component != null) {
            
if (component instanceof JComponent &&
                   
((JComponent)component).getFlag(ANCESTOR_USING_BUFFER)) {
                
return true;
            
}
            
component = component.getParent();
        
}
        
return false;
    
}

    
private void adjustPaintFlags() {
        
JComponent jparent;
        
Container parent;
        
for(parent = getParent() ; parent != null ; parent =
            
parent.getParent()) {
            
if(parent instanceof