1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package javax.swing;
  27 
  28 import java.awt.*;
  29 
  30 import java.beans.*;
  31 
  32 import javax.swing.event.InternalFrameEvent;
  33 import javax.swing.event.InternalFrameListener;
  34 import javax.swing.plaf.*;
  35 
  36 import javax.accessibility.*;
  37 
  38 import java.io.ObjectOutputStream;
  39 import java.io.IOException;
  40 
  41 import sun.awt.AppContext;
  42 import sun.swing.SwingUtilities2;
  43 
  44 
  45 /**
  46  * A lightweight object that provides many of the features of
  47  * a native frame, including dragging, closing, becoming an icon,
  48  * resizing, title display, and support for a menu bar.
  49  * For task-oriented documentation and examples of using internal frames,
  50  * see <a
  51  href="http://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html" target="_top">How to Use Internal Frames</a>,
  52  * a section in <em>The Java Tutorial</em>.
  53  *
  54  * <p>
  55  *
  56  * Generally,
  57  * you add <code>JInternalFrame</code>s to a <code>JDesktopPane</code>. The UI
  58  * delegates the look-and-feel-specific actions to the
  59  * <code>DesktopManager</code>
  60  * object maintained by the <code>JDesktopPane</code>.
  61  * <p>
  62  * The <code>JInternalFrame</code> content pane
  63  * is where you add child components.
  64  * As a convenience, the {@code add}, {@code remove}, and {@code setLayout}
  65  * methods of this class are overridden, so that they delegate calls
  66  * to the corresponding methods of the {@code ContentPane}.
  67  * For example, you can add a child component to an internal frame as follows:
  68  * <pre>
  69  *       internalFrame.add(child);
  70  * </pre>
  71  * And the child will be added to the contentPane.
  72  * The content pane is actually managed by an instance of
  73  * <code>JRootPane</code>,
  74  * which also manages a layout pane, glass pane, and
  75  * optional menu bar for the internal frame. Please see the
  76  * <code>JRootPane</code>
  77  * documentation for a complete description of these components.
  78  * Refer to {@link javax.swing.RootPaneContainer}
  79  * for details on adding, removing and setting the <code>LayoutManager</code>
  80  * of a <code>JInternalFrame</code>.
  81  * <p>
  82  * <strong>Warning:</strong> Swing is not thread safe. For more
  83  * information see <a
  84  * href="package-summary.html#threading">Swing's Threading
  85  * Policy</a>.
  86  * <p>
  87  * <strong>Warning:</strong>
  88  * Serialized objects of this class will not be compatible with
  89  * future Swing releases. The current serialization support is
  90  * appropriate for short term storage or RMI between applications running
  91  * the same version of Swing.  As of 1.4, support for long term storage
  92  * of all JavaBeans&trade;
  93  * has been added to the <code>java.beans</code> package.
  94  * Please see {@link java.beans.XMLEncoder}.
  95  *
  96  * @see InternalFrameEvent
  97  * @see JDesktopPane
  98  * @see DesktopManager
  99  * @see JInternalFrame.JDesktopIcon
 100  * @see JRootPane
 101  * @see javax.swing.RootPaneContainer
 102  *
 103  * @author David Kloba
 104  * @author Rich Schiavi
 105  * @since 1.2
 106  */
 107 @JavaBean(defaultProperty = "JMenuBar", description = "A frame container which is contained within another window.")
 108 @SwingContainer(delegate = "getContentPane")
 109 @SuppressWarnings("serial") // Same-version serialization only
 110 public class JInternalFrame extends JComponent implements
 111         Accessible, WindowConstants,
 112         RootPaneContainer
 113 {
 114     /**
 115      * @see #getUIClassID
 116      * @see #readObject
 117      */
 118     private static final String uiClassID = "InternalFrameUI";
 119 
 120     /**
 121      * The <code>JRootPane</code> instance that manages the
 122      * content pane
 123      * and optional menu bar for this internal frame, as well as the
 124      * glass pane.
 125      *
 126      * @see JRootPane
 127      * @see RootPaneContainer
 128      */
 129     protected JRootPane rootPane;
 130 
 131     /**
 132      * If true then calls to <code>add</code> and <code>setLayout</code>
 133      * will be forwarded to the <code>contentPane</code>. This is initially
 134      * false, but is set to true when the <code>JInternalFrame</code> is
 135      * constructed.
 136      *
 137      * @see #isRootPaneCheckingEnabled
 138      * @see #setRootPaneCheckingEnabled
 139      * @see javax.swing.RootPaneContainer
 140      */
 141     protected boolean rootPaneCheckingEnabled = false;
 142 
 143     /** The frame can be closed. */
 144     protected boolean closable;
 145     /** The frame has been closed. */
 146     protected boolean isClosed;
 147     /** The frame can be expanded to the size of the desktop pane. */
 148     protected boolean maximizable;
 149     /**
 150      * The frame has been expanded to its maximum size.
 151      * @see #maximizable
 152      */
 153     protected boolean isMaximum;
 154     /**
 155      * The frame can "iconified" (shrunk down and displayed as
 156      * an icon-image).
 157      * @see JInternalFrame.JDesktopIcon
 158      * @see #setIconifiable
 159      */
 160     protected boolean iconable;
 161     /**
 162      * The frame has been iconified.
 163      * @see #isIcon()
 164      */
 165     protected boolean isIcon;
 166     /** The frame's size can be changed. */
 167     protected boolean resizable;
 168     /** The frame is currently selected. */
 169     protected boolean isSelected;
 170     /** The icon shown in the top-left corner of this internal frame. */
 171     protected Icon frameIcon;
 172     /** The title displayed in this internal frame's title bar. */
 173     protected String  title;
 174     /**
 175      * The icon that is displayed when this internal frame is iconified.
 176      * @see #iconable
 177      */
 178     protected JDesktopIcon desktopIcon;
 179 
 180     private Cursor lastCursor;
 181 
 182     private boolean opened;
 183 
 184     private Rectangle normalBounds = null;
 185 
 186     private int defaultCloseOperation = DISPOSE_ON_CLOSE;
 187 
 188     /**
 189      * Contains the Component that focus is to go when
 190      * <code>restoreSubcomponentFocus</code> is invoked, that is,
 191      * <code>restoreSubcomponentFocus</code> sets this to the value returned
 192      * from <code>getMostRecentFocusOwner</code>.
 193      */
 194     private Component lastFocusOwner;
 195 
 196     /** Bound property name. */
 197     public final static String CONTENT_PANE_PROPERTY = "contentPane";
 198     /** Bound property name. */
 199     public final static String MENU_BAR_PROPERTY = "JMenuBar";
 200     /** Bound property name. */
 201     public final static String TITLE_PROPERTY = "title";
 202     /** Bound property name. */
 203     public final static String LAYERED_PANE_PROPERTY = "layeredPane";
 204     /** Bound property name. */
 205     public final static String ROOT_PANE_PROPERTY = "rootPane";
 206     /** Bound property name. */
 207     public final static String GLASS_PANE_PROPERTY = "glassPane";
 208     /** Bound property name. */
 209     public final static String FRAME_ICON_PROPERTY = "frameIcon";
 210 
 211     /**
 212      * Constrained property name indicated that this frame has
 213      * selected status.
 214      */
 215     public final static String IS_SELECTED_PROPERTY = "selected";
 216     /** Constrained property name indicating that the internal frame is closed. */
 217     public final static String IS_CLOSED_PROPERTY = "closed";
 218     /** Constrained property name indicating that the internal frame is maximized. */
 219     public final static String IS_MAXIMUM_PROPERTY = "maximum";
 220     /** Constrained property name indicating that the internal frame is iconified. */
 221     public final static String IS_ICON_PROPERTY = "icon";
 222 
 223     private static final Object PROPERTY_CHANGE_LISTENER_KEY =
 224         new StringBuilder("InternalFramePropertyChangeListener");
 225 
 226     private static void addPropertyChangeListenerIfNecessary() {
 227         if (AppContext.getAppContext().get(PROPERTY_CHANGE_LISTENER_KEY) ==
 228             null) {
 229             PropertyChangeListener focusListener =
 230                 new FocusPropertyChangeListener();
 231 
 232             AppContext.getAppContext().put(PROPERTY_CHANGE_LISTENER_KEY,
 233                 focusListener);
 234 
 235             KeyboardFocusManager.getCurrentKeyboardFocusManager().
 236                 addPropertyChangeListener(focusListener);
 237         }
 238     }
 239 
 240     private static class FocusPropertyChangeListener implements
 241         PropertyChangeListener {
 242         public void propertyChange(PropertyChangeEvent e) {
 243             if (e.getPropertyName() == "permanentFocusOwner") {
 244                 updateLastFocusOwner((Component)e.getNewValue());
 245             }
 246         }
 247     }
 248 
 249     private static void updateLastFocusOwner(Component component) {
 250         if (component != null) {
 251             Component parent = component;
 252             while (parent != null && !(parent instanceof Window)) {
 253                 if (parent instanceof JInternalFrame) {
 254                     // Update lastFocusOwner for parent.
 255                     ((JInternalFrame)parent).setLastFocusOwner(component);
 256                 }
 257                 parent = parent.getParent();
 258             }
 259         }
 260     }
 261 
 262     /**
 263      * Creates a non-resizable, non-closable, non-maximizable,
 264      * non-iconifiable <code>JInternalFrame</code> with no title.
 265      */
 266     public JInternalFrame() {
 267         this("", false, false, false, false);
 268     }
 269 
 270     /**
 271      * Creates a non-resizable, non-closable, non-maximizable,
 272      * non-iconifiable <code>JInternalFrame</code> with the specified title.
 273      * Note that passing in a <code>null</code> <code>title</code> results in
 274      * unspecified behavior and possibly an exception.
 275      *
 276      * @param title  the non-<code>null</code> <code>String</code>
 277      *     to display in the title bar
 278      */
 279     public JInternalFrame(String title) {
 280         this(title, false, false, false, false);
 281     }
 282 
 283     /**
 284      * Creates a non-closable, non-maximizable, non-iconifiable
 285      * <code>JInternalFrame</code> with the specified title
 286      * and resizability.
 287      *
 288      * @param title      the <code>String</code> to display in the title bar
 289      * @param resizable  if <code>true</code>, the internal frame can be resized
 290      */
 291     public JInternalFrame(String title, boolean resizable) {
 292         this(title, resizable, false, false, false);
 293     }
 294 
 295     /**
 296      * Creates a non-maximizable, non-iconifiable <code>JInternalFrame</code>
 297      * with the specified title, resizability, and
 298      * closability.
 299      *
 300      * @param title      the <code>String</code> to display in the title bar
 301      * @param resizable  if <code>true</code>, the internal frame can be resized
 302      * @param closable   if <code>true</code>, the internal frame can be closed
 303      */
 304     public JInternalFrame(String title, boolean resizable, boolean closable) {
 305         this(title, resizable, closable, false, false);
 306     }
 307 
 308     /**
 309      * Creates a non-iconifiable <code>JInternalFrame</code>
 310      * with the specified title,
 311      * resizability, closability, and maximizability.
 312      *
 313      * @param title       the <code>String</code> to display in the title bar
 314      * @param resizable   if <code>true</code>, the internal frame can be resized
 315      * @param closable    if <code>true</code>, the internal frame can be closed
 316      * @param maximizable if <code>true</code>, the internal frame can be maximized
 317      */
 318     public JInternalFrame(String title, boolean resizable, boolean closable,
 319                           boolean maximizable) {
 320         this(title, resizable, closable, maximizable, false);
 321     }
 322 
 323     /**
 324      * Creates a <code>JInternalFrame</code> with the specified title,
 325      * resizability, closability, maximizability, and iconifiability.
 326      * All <code>JInternalFrame</code> constructors use this one.
 327      *
 328      * @param title       the <code>String</code> to display in the title bar
 329      * @param resizable   if <code>true</code>, the internal frame can be resized
 330      * @param closable    if <code>true</code>, the internal frame can be closed
 331      * @param maximizable if <code>true</code>, the internal frame can be maximized
 332      * @param iconifiable if <code>true</code>, the internal frame can be iconified
 333      */
 334     public JInternalFrame(String title, boolean resizable, boolean closable,
 335                                 boolean maximizable, boolean iconifiable) {
 336 
 337         setRootPane(createRootPane());
 338         setLayout(new BorderLayout());
 339         this.title = title;
 340         this.resizable = resizable;
 341         this.closable = closable;
 342         this.maximizable = maximizable;
 343         isMaximum = false;
 344         this.iconable = iconifiable;
 345         isIcon = false;
 346         setVisible(false);
 347         setRootPaneCheckingEnabled(true);
 348         desktopIcon = new JDesktopIcon(this);
 349         updateUI();
 350         sun.awt.SunToolkit.checkAndSetPolicy(this);
 351         addPropertyChangeListenerIfNecessary();
 352     }
 353 
 354     /**
 355      * Called by the constructor to set up the <code>JRootPane</code>.
 356      * @return  a new <code>JRootPane</code>
 357      * @see JRootPane
 358      */
 359     protected JRootPane createRootPane() {
 360         return new JRootPane();
 361     }
 362 
 363     /**
 364      * Returns the look-and-feel object that renders this component.
 365      *
 366      * @return the <code>InternalFrameUI</code> object that renders
 367      *          this component
 368      */
 369     public InternalFrameUI getUI() {
 370         return (InternalFrameUI)ui;
 371     }
 372 
 373     /**
 374      * Sets the UI delegate for this <code>JInternalFrame</code>.
 375      * @param ui  the UI delegate
 376      */
 377     @BeanProperty(hidden = true, visualUpdate = true, description
 378             = "The UI object that implements the Component's LookAndFeel.")
 379     public void setUI(InternalFrameUI ui) {
 380         boolean checkingEnabled = isRootPaneCheckingEnabled();
 381         try {
 382             setRootPaneCheckingEnabled(false);
 383             super.setUI(ui);
 384         }
 385         finally {
 386             setRootPaneCheckingEnabled(checkingEnabled);
 387         }
 388     }
 389 
 390     /**
 391      * Notification from the <code>UIManager</code> that the look and feel
 392      * has changed.
 393      * Replaces the current UI object with the latest version from the
 394      * <code>UIManager</code>.
 395      *
 396      * @see JComponent#updateUI
 397      */
 398     public void updateUI() {
 399         setUI((InternalFrameUI)UIManager.getUI(this));
 400         invalidate();
 401         if (desktopIcon != null) {
 402             desktopIcon.updateUIWhenHidden();
 403         }
 404     }
 405 
 406     /* This method is called if <code>updateUI</code> was called
 407      * on the associated
 408      * JDesktopIcon.  It's necessary to avoid infinite recursion.
 409      */
 410     void updateUIWhenHidden() {
 411         setUI((InternalFrameUI)UIManager.getUI(this));
 412         invalidate();
 413         Component[] children = getComponents();
 414         if (children != null) {
 415             for (Component child : children) {
 416                 SwingUtilities.updateComponentTreeUI(child);
 417             }
 418         }
 419     }
 420 
 421 
 422     /**
 423      * Returns the name of the look-and-feel
 424      * class that renders this component.
 425      *
 426      * @return the string "InternalFrameUI"
 427      *
 428      * @see JComponent#getUIClassID
 429      * @see UIDefaults#getUI
 430      */
 431     @BeanProperty(bound = false, description
 432             = "UIClassID")
 433     public String getUIClassID() {
 434         return uiClassID;
 435     }
 436 
 437     /**
 438      * Returns whether calls to <code>add</code> and
 439      * <code>setLayout</code> are forwarded to the <code>contentPane</code>.
 440      *
 441      * @return true if <code>add</code> and <code>setLayout</code>
 442      *         are forwarded; false otherwise
 443      *
 444      * @see #addImpl
 445      * @see #setLayout
 446      * @see #setRootPaneCheckingEnabled
 447      * @see javax.swing.RootPaneContainer
 448      */
 449     protected boolean isRootPaneCheckingEnabled() {
 450         return rootPaneCheckingEnabled;
 451     }
 452 
 453     /**
 454      * Sets whether calls to <code>add</code> and
 455      * <code>setLayout</code> are forwarded to the <code>contentPane</code>.
 456      *
 457      * @param enabled  true if <code>add</code> and <code>setLayout</code>
 458      *        are forwarded, false if they should operate directly on the
 459      *        <code>JInternalFrame</code>.
 460      *
 461      * @see #addImpl
 462      * @see #setLayout
 463      * @see #isRootPaneCheckingEnabled
 464      * @see javax.swing.RootPaneContainer
 465      */
 466     @BeanProperty(hidden = true, description
 467             = "Whether the add and setLayout methods are forwarded")
 468     protected void setRootPaneCheckingEnabled(boolean enabled) {
 469         rootPaneCheckingEnabled = enabled;
 470     }
 471 
 472     /**
 473      * Adds the specified child <code>Component</code>.
 474      * This method is overridden to conditionally forward calls to the
 475      * <code>contentPane</code>.
 476      * By default, children are added to the <code>contentPane</code> instead
 477      * of the frame, refer to {@link javax.swing.RootPaneContainer} for
 478      * details.
 479      *
 480      * @param comp the component to be enhanced
 481      * @param constraints the constraints to be respected
 482      * @param index the index
 483      * @exception IllegalArgumentException if <code>index</code> is invalid
 484      * @exception IllegalArgumentException if adding the container's parent
 485      *                  to itself
 486      * @exception IllegalArgumentException if adding a window to a container
 487      *
 488      * @see #setRootPaneCheckingEnabled
 489      * @see javax.swing.RootPaneContainer
 490      */
 491     protected void addImpl(Component comp, Object constraints, int index) {
 492         if(isRootPaneCheckingEnabled()) {
 493             getContentPane().add(comp, constraints, index);
 494         }
 495         else {
 496             super.addImpl(comp, constraints, index);
 497         }
 498     }
 499 
 500     /**
 501      * Removes the specified component from the container. If
 502      * <code>comp</code> is not a child of the <code>JInternalFrame</code>
 503      * this will forward the call to the <code>contentPane</code>.
 504      *
 505      * @param comp the component to be removed
 506      * @throws NullPointerException if <code>comp</code> is null
 507      * @see #add
 508      * @see javax.swing.RootPaneContainer
 509      */
 510     public void remove(Component comp) {
 511         int oldCount = getComponentCount();
 512         super.remove(comp);
 513         if (oldCount == getComponentCount()) {
 514             getContentPane().remove(comp);
 515         }
 516     }
 517 
 518 
 519     /**
 520      * Ensures that, by default, the layout of this component cannot be set.
 521      * Overridden to conditionally forward the call to the
 522      * <code>contentPane</code>.
 523      * Refer to {@link javax.swing.RootPaneContainer} for
 524      * more information.
 525      *
 526      * @param manager the <code>LayoutManager</code>
 527      * @see #setRootPaneCheckingEnabled
 528      */
 529     public void setLayout(LayoutManager manager) {
 530         if(isRootPaneCheckingEnabled()) {
 531             getContentPane().setLayout(manager);
 532         }
 533         else {
 534             super.setLayout(manager);
 535         }
 536     }
 537 
 538 
 539 //////////////////////////////////////////////////////////////////////////
 540 /// Property Methods
 541 //////////////////////////////////////////////////////////////////////////
 542 
 543     /**
 544      * Returns the current <code>JMenuBar</code> for this
 545      * <code>JInternalFrame</code>, or <code>null</code>
 546      * if no menu bar has been set.
 547      * @return the current menu bar, or <code>null</code> if none has been set
 548      *
 549      * @deprecated As of Swing version 1.0.3,
 550      * replaced by <code>getJMenuBar()</code>.
 551      */
 552     @Deprecated
 553     public JMenuBar getMenuBar() {
 554       return getRootPane().getMenuBar();
 555     }
 556 
 557     /**
 558      * Returns the current <code>JMenuBar</code> for this
 559      * <code>JInternalFrame</code>, or <code>null</code>
 560      * if no menu bar has been set.
 561      *
 562      * @return  the <code>JMenuBar</code> used by this internal frame
 563      * @see #setJMenuBar
 564      */
 565     public JMenuBar getJMenuBar() {
 566         return getRootPane().getJMenuBar();
 567     }
 568 
 569     /**
 570      * Sets the <code>menuBar</code> property for this <code>JInternalFrame</code>.
 571      *
 572      * @param m  the <code>JMenuBar</code> to use in this internal frame
 573      * @see #getJMenuBar
 574      * @deprecated As of Swing version 1.0.3
 575      *  replaced by <code>setJMenuBar(JMenuBar m)</code>.
 576      */
 577     @Deprecated
 578     public void setMenuBar(JMenuBar m) {
 579         JMenuBar oldValue = getMenuBar();
 580         getRootPane().setJMenuBar(m);
 581         firePropertyChange(MENU_BAR_PROPERTY, oldValue, m);
 582     }
 583 
 584     /**
 585      * Sets the <code>menuBar</code> property for this <code>JInternalFrame</code>.
 586      *
 587      * @param m  the <code>JMenuBar</code> to use in this internal frame
 588      * @see #getJMenuBar
 589      */
 590     @BeanProperty(preferred = true, description
 591             = "The menu bar for accessing pulldown menus from this internal frame.")
 592     public void setJMenuBar(JMenuBar m){
 593         JMenuBar oldValue = getMenuBar();
 594         getRootPane().setJMenuBar(m);
 595         firePropertyChange(MENU_BAR_PROPERTY, oldValue, m);
 596     }
 597 
 598     // implements javax.swing.RootPaneContainer
 599     /**
 600      * Returns the content pane for this internal frame.
 601      * @return the content pane
 602      */
 603     public Container getContentPane() {
 604         return getRootPane().getContentPane();
 605     }
 606 
 607 
 608     /**
 609      * Sets this <code>JInternalFrame</code>'s <code>contentPane</code>
 610      * property.
 611      *
 612      * @param c  the content pane for this internal frame
 613      *
 614      * @exception java.awt.IllegalComponentStateException (a runtime
 615      *           exception) if the content pane parameter is <code>null</code>
 616      * @see RootPaneContainer#getContentPane
 617      */
 618     @BeanProperty(hidden = true, description
 619             = "The client area of the internal frame where child components are normally inserted.")
 620     public void setContentPane(Container c) {
 621         Container oldValue = getContentPane();
 622         getRootPane().setContentPane(c);
 623         firePropertyChange(CONTENT_PANE_PROPERTY, oldValue, c);
 624     }
 625 
 626     /**
 627      * Returns the layered pane for this internal frame.
 628      *
 629      * @return a <code>JLayeredPane</code> object
 630      * @see RootPaneContainer#setLayeredPane
 631      * @see RootPaneContainer#getLayeredPane
 632      */
 633     public JLayeredPane getLayeredPane() {
 634         return getRootPane().getLayeredPane();
 635     }
 636 
 637     /**
 638      * Sets this <code>JInternalFrame</code>'s
 639      * <code>layeredPane</code> property.
 640      *
 641      * @param layered the <code>JLayeredPane</code> for this internal frame
 642      *
 643      * @exception java.awt.IllegalComponentStateException (a runtime
 644      *           exception) if the layered pane parameter is <code>null</code>
 645      * @see RootPaneContainer#setLayeredPane
 646      */
 647     @BeanProperty(hidden = true, description
 648             = "The pane which holds the various desktop layers.")
 649     public void setLayeredPane(JLayeredPane layered) {
 650         JLayeredPane oldValue = getLayeredPane();
 651         getRootPane().setLayeredPane(layered);
 652         firePropertyChange(LAYERED_PANE_PROPERTY, oldValue, layered);
 653     }
 654 
 655     /**
 656      * Returns the glass pane for this internal frame.
 657      *
 658      * @return the glass pane
 659      * @see RootPaneContainer#setGlassPane
 660      */
 661     public Component getGlassPane() {
 662         return getRootPane().getGlassPane();
 663     }
 664 
 665     /**
 666      * Sets this <code>JInternalFrame</code>'s
 667      * <code>glassPane</code> property.
 668      *
 669      * @param glass the glass pane for this internal frame
 670      * @see RootPaneContainer#getGlassPane
 671      */
 672     @BeanProperty(hidden = true, description
 673             = "A transparent pane used for menu rendering.")
 674     public void setGlassPane(Component glass) {
 675         Component oldValue = getGlassPane();
 676         getRootPane().setGlassPane(glass);
 677         firePropertyChange(GLASS_PANE_PROPERTY, oldValue, glass);
 678     }
 679 
 680     /**
 681      * Returns the <code>rootPane</code> object for this internal frame.
 682      *
 683      * @return the <code>rootPane</code> property
 684      * @see RootPaneContainer#getRootPane
 685      */
 686     @BeanProperty(hidden = true, description
 687             = "The root pane used by this internal frame.")
 688     public JRootPane getRootPane() {
 689         return rootPane;
 690     }
 691 
 692 
 693     /**
 694      * Sets the <code>rootPane</code> property
 695      * for this <code>JInternalFrame</code>.
 696      * This method is called by the constructor.
 697      *
 698      * @param root  the new <code>JRootPane</code> object
 699      */
 700     protected void setRootPane(JRootPane root) {
 701         if(rootPane != null) {
 702             remove(rootPane);
 703         }
 704         JRootPane oldValue = getRootPane();
 705         rootPane = root;
 706         if(rootPane != null) {
 707             boolean checkingEnabled = isRootPaneCheckingEnabled();
 708             try {
 709                 setRootPaneCheckingEnabled(false);
 710                 add(rootPane, BorderLayout.CENTER);
 711             }
 712             finally {
 713                 setRootPaneCheckingEnabled(checkingEnabled);
 714             }
 715         }
 716         firePropertyChange(ROOT_PANE_PROPERTY, oldValue, root);
 717     }
 718 
 719     /**
 720      * Sets whether this <code>JInternalFrame</code> can be closed by
 721      * some user action.
 722      * @param b a boolean value, where <code>true</code> means this internal frame can be closed
 723      */
 724     @BeanProperty(preferred = true, description
 725             = "Indicates whether this internal frame can be closed.")
 726     public void setClosable(boolean b) {
 727         Boolean oldValue = closable ? Boolean.TRUE : Boolean.FALSE;
 728         Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE;
 729         closable = b;
 730         firePropertyChange("closable", oldValue, newValue);
 731     }
 732 
 733     /**
 734      * Returns whether this <code>JInternalFrame</code> can be closed by
 735      * some user action.
 736      * @return <code>true</code> if this internal frame can be closed
 737      */
 738     public boolean isClosable() {
 739         return closable;
 740     }
 741 
 742     /**
 743      * Returns whether this <code>JInternalFrame</code> is currently closed.
 744      * @return <code>true</code> if this internal frame is closed, <code>false</code> otherwise
 745      */
 746     public boolean isClosed() {
 747         return isClosed;
 748     }
 749 
 750     /**
 751      * Closes this internal frame if the argument is <code>true</code>.
 752      * Do not invoke this method with a <code>false</code> argument;
 753      * the result of invoking <code>setClosed(false)</code>
 754      * is unspecified.
 755      *
 756      * <p>
 757      *
 758      * If the internal frame is already closed,
 759      * this method does nothing and returns immediately.
 760      * Otherwise,
 761      * this method begins by firing
 762      * an <code>INTERNAL_FRAME_CLOSING</code> event.
 763      * Then this method sets the <code>closed</code> property to <code>true</code>
 764      * unless a listener vetoes the property change.
 765      * This method finishes by making the internal frame
 766      * invisible and unselected,
 767      * and then firing an <code>INTERNAL_FRAME_CLOSED</code> event.
 768      *
 769      * <p>
 770      *
 771      * <b>Note:</b>
 772      * To reuse an internal frame that has been closed,
 773      * you must add it to a container
 774      * (even if you never removed it from its previous container).
 775      * Typically, this container will be the <code>JDesktopPane</code>
 776      * that previously contained the internal frame.
 777      *
 778      * @param b must be <code>true</code>
 779      *
 780      * @exception PropertyVetoException when the attempt to set the
 781      *            property is vetoed by the <code>JInternalFrame</code>
 782      *
 783      * @see #isClosed()
 784      * @see #setDefaultCloseOperation
 785      * @see #dispose
 786      * @see javax.swing.event.InternalFrameEvent#INTERNAL_FRAME_CLOSING
 787      */
 788     @BeanProperty(description
 789             = "Indicates whether this internal frame has been closed.")
 790     public void setClosed(boolean b) throws PropertyVetoException {
 791         if (isClosed == b) {
 792             return;
 793         }
 794 
 795         Boolean oldValue = isClosed ? Boolean.TRUE : Boolean.FALSE;
 796         Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE;
 797         if (b) {
 798           fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING);
 799         }
 800         fireVetoableChange(IS_CLOSED_PROPERTY, oldValue, newValue);
 801         isClosed = b;
 802         if (isClosed) {
 803           setVisible(false);
 804         }
 805         firePropertyChange(IS_CLOSED_PROPERTY, oldValue, newValue);
 806         if (isClosed) {
 807           dispose();
 808         } else if (!opened) {
 809           /* this bogus -- we haven't defined what
 810              setClosed(false) means. */
 811           //        fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED);
 812           //            opened = true;
 813         }
 814     }
 815 
 816     /**
 817      * Sets whether the <code>JInternalFrame</code> can be resized by some
 818      * user action.
 819      *
 820      * @param b  a boolean, where <code>true</code> means this internal frame can be resized
 821      */
 822     @BeanProperty(preferred = true, description
 823             = "Determines whether this internal frame can be resized by the user.")
 824     public void setResizable(boolean b) {
 825         Boolean oldValue = resizable ? Boolean.TRUE : Boolean.FALSE;
 826         Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE;
 827         resizable = b;
 828         firePropertyChange("resizable", oldValue, newValue);
 829     }
 830 
 831     /**
 832      * Returns whether the <code>JInternalFrame</code> can be resized
 833      * by some user action.
 834      *
 835      * @return <code>true</code> if this internal frame can be resized, <code>false</code> otherwise
 836      */
 837     public boolean isResizable() {
 838         // don't allow resizing when maximized.
 839         return isMaximum ? false : resizable;
 840     }
 841 
 842     /**
 843      * Sets the <code>iconable</code> property,
 844      * which must be <code>true</code>
 845      * for the user to be able to
 846      * make the <code>JInternalFrame</code> an icon.
 847      * Some look and feels might not implement iconification;
 848      * they will ignore this property.
 849      *
 850      * @param b  a boolean, where <code>true</code> means this internal frame can be iconified
 851      */
 852     @BeanProperty(preferred = true, description
 853             = "Determines whether this internal frame can be iconified.")
 854     public void setIconifiable(boolean b) {
 855         Boolean oldValue = iconable ? Boolean.TRUE : Boolean.FALSE;
 856         Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE;
 857         iconable = b;
 858         firePropertyChange("iconable", oldValue, newValue);
 859     }
 860 
 861     /**
 862      * Gets the <code>iconable</code> property,
 863      * which by default is <code>false</code>.
 864      *
 865      * @return the value of the <code>iconable</code> property.
 866      *
 867      * @see #setIconifiable
 868      */
 869     public boolean isIconifiable() {
 870         return iconable;
 871     }
 872 
 873     /**
 874      * Returns whether the <code>JInternalFrame</code> is currently iconified.
 875      *
 876      * @return <code>true</code> if this internal frame is iconified
 877      */
 878     public boolean isIcon() {
 879         return isIcon;
 880     }
 881 
 882     /**
 883      * Iconifies or de-iconifies this internal frame,
 884      * if the look and feel supports iconification.
 885      * If the internal frame's state changes to iconified,
 886      * this method fires an <code>INTERNAL_FRAME_ICONIFIED</code> event.
 887      * If the state changes to de-iconified,
 888      * an <code>INTERNAL_FRAME_DEICONIFIED</code> event is fired.
 889      *
 890      * @param b a boolean, where <code>true</code> means to iconify this internal frame and
 891      *          <code>false</code> means to de-iconify it
 892      * @exception PropertyVetoException when the attempt to set the
 893      *            property is vetoed by the <code>JInternalFrame</code>
 894      *
 895      * @see InternalFrameEvent#INTERNAL_FRAME_ICONIFIED
 896      * @see InternalFrameEvent#INTERNAL_FRAME_DEICONIFIED
 897      */
 898     @BeanProperty(description
 899             = "The image displayed when this internal frame is minimized.")
 900     public void setIcon(boolean b) throws PropertyVetoException {
 901         if (isIcon == b) {
 902             return;
 903         }
 904 
 905         /* If an internal frame is being iconified before it has a
 906            parent, (e.g., client wants it to start iconic), create the
 907            parent if possible so that we can place the icon in its
 908            proper place on the desktop. I am not sure the call to
 909            validate() is necessary, since we are not going to display
 910            this frame yet */
 911         firePropertyChange("ancestor", null, getParent());
 912 
 913         Boolean oldValue = isIcon ? Boolean.TRUE : Boolean.FALSE;
 914         Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE;
 915         fireVetoableChange(IS_ICON_PROPERTY, oldValue, newValue);
 916         isIcon = b;
 917         firePropertyChange(IS_ICON_PROPERTY, oldValue, newValue);
 918         if (b)
 919           fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_ICONIFIED);
 920         else
 921           fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_DEICONIFIED);
 922     }
 923 
 924     /**
 925      * Sets the <code>maximizable</code> property,
 926      * which determines whether the <code>JInternalFrame</code>
 927      * can be maximized by
 928      * some user action.
 929      * Some look and feels might not support maximizing internal frames;
 930      * they will ignore this property.
 931      *
 932      * @param b <code>true</code> to specify that this internal frame should be maximizable; <code>false</code> to specify that it should not be
 933      */
 934     @BeanProperty(preferred = true, description
 935             = "Determines whether this internal frame can be maximized.")
 936     public void setMaximizable(boolean b) {
 937         Boolean oldValue = maximizable ? Boolean.TRUE : Boolean.FALSE;
 938         Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE;
 939         maximizable = b;
 940         firePropertyChange("maximizable", oldValue, newValue);
 941     }
 942 
 943     /**
 944      * Gets the value of the <code>maximizable</code> property.
 945      *
 946      * @return the value of the <code>maximizable</code> property
 947      * @see #setMaximizable
 948      */
 949     public boolean isMaximizable() {
 950         return maximizable;
 951     }
 952 
 953     /**
 954      * Returns whether the <code>JInternalFrame</code> is currently maximized.
 955      *
 956      * @return <code>true</code> if this internal frame is maximized, <code>false</code> otherwise
 957      */
 958     public boolean isMaximum() {
 959         return isMaximum;
 960     }
 961 
 962     /**
 963      * Maximizes and restores this internal frame.  A maximized frame is resized to
 964      * fully fit the <code>JDesktopPane</code> area associated with the
 965      * <code>JInternalFrame</code>.
 966      * A restored frame's size is set to the <code>JInternalFrame</code>'s
 967      * actual size.
 968      *
 969      * @param b  a boolean, where <code>true</code> maximizes this internal frame and <code>false</code>
 970      *           restores it
 971      * @exception PropertyVetoException when the attempt to set the
 972      *            property is vetoed by the <code>JInternalFrame</code>
 973      */
 974     @BeanProperty(description
 975             = "Indicates whether this internal frame is maximized.")
 976     public void setMaximum(boolean b) throws PropertyVetoException {
 977         if (isMaximum == b) {
 978             return;
 979         }
 980 
 981         Boolean oldValue = isMaximum ? Boolean.TRUE : Boolean.FALSE;
 982         Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE;
 983         fireVetoableChange(IS_MAXIMUM_PROPERTY, oldValue, newValue);
 984         /* setting isMaximum above the event firing means that
 985            property listeners that, for some reason, test it will
 986            get it wrong... See, for example, getNormalBounds() */
 987         isMaximum = b;
 988         firePropertyChange(IS_MAXIMUM_PROPERTY, oldValue, newValue);
 989     }
 990 
 991     /**
 992      * Returns the title of the <code>JInternalFrame</code>.
 993      *
 994      * @return a <code>String</code> containing this internal frame's title
 995      * @see #setTitle
 996      */
 997     public String getTitle() {
 998         return title;
 999     }
1000 
1001     /**
1002      * Sets the <code>JInternalFrame</code> title. <code>title</code>
1003      * may have a <code>null</code> value.
1004      * @see #getTitle
1005      *
1006      * @param title  the <code>String</code> to display in the title bar
1007      */
1008     @BeanProperty(preferred = true, description
1009             = "The text displayed in the title bar.")
1010     public void setTitle(String title) {
1011         String oldValue = this.title;
1012         this.title = title;
1013         firePropertyChange(TITLE_PROPERTY, oldValue, title);
1014     }
1015 
1016     /**
1017      * Selects or deselects the internal frame
1018      * if it's showing.
1019      * A <code>JInternalFrame</code> normally draws its title bar
1020      * differently if it is
1021      * the selected frame, which indicates to the user that this
1022      * internal frame has the focus.
1023      * When this method changes the state of the internal frame
1024      * from deselected to selected, it fires an
1025      * <code>InternalFrameEvent.INTERNAL_FRAME_ACTIVATED</code> event.
1026      * If the change is from selected to deselected,
1027      * an <code>InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED</code> event
1028      * is fired.
1029      *
1030      * @param selected  a boolean, where <code>true</code> means this internal frame
1031      *                  should become selected (currently active)
1032      *                  and <code>false</code> means it should become deselected
1033      * @exception PropertyVetoException when the attempt to set the
1034      *            property is vetoed by the <code>JInternalFrame</code>
1035      *
1036      * @see #isShowing
1037      * @see InternalFrameEvent#INTERNAL_FRAME_ACTIVATED
1038      * @see InternalFrameEvent#INTERNAL_FRAME_DEACTIVATED
1039      */
1040     @BeanProperty(description
1041             = "Indicates whether this internal frame is currently the active frame.")
1042     public void setSelected(boolean selected) throws PropertyVetoException {
1043        // The InternalFrame may already be selected, but the focus
1044        // may be outside it, so restore the focus to the subcomponent
1045        // which previously had it. See Bug 4302764.
1046         if (selected && isSelected) {
1047             restoreSubcomponentFocus();
1048             return;
1049         }
1050         // The internal frame or the desktop icon must be showing to allow
1051         // selection.  We may deselect even if neither is showing.
1052         if ((isSelected == selected) || (selected &&
1053             (isIcon ? !desktopIcon.isShowing() : !isShowing()))) {
1054             return;
1055         }
1056 
1057         Boolean oldValue = isSelected ? Boolean.TRUE : Boolean.FALSE;
1058         Boolean newValue = selected ? Boolean.TRUE : Boolean.FALSE;
1059         fireVetoableChange(IS_SELECTED_PROPERTY, oldValue, newValue);
1060 
1061         /* We don't want to leave focus in the previously selected
1062            frame, so we have to set it to *something* in case it
1063            doesn't get set in some other way (as if a user clicked on
1064            a component that doesn't request focus).  If this call is
1065            happening because the user clicked on a component that will
1066            want focus, then it will get transfered there later.
1067 
1068            We test for parent.isShowing() above, because AWT throws a
1069            NPE if you try to request focus on a lightweight before its
1070            parent has been made visible */
1071 
1072         if (selected) {
1073             restoreSubcomponentFocus();
1074         }
1075 
1076         isSelected = selected;
1077         firePropertyChange(IS_SELECTED_PROPERTY, oldValue, newValue);
1078         if (isSelected)
1079           fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_ACTIVATED);
1080         else
1081           fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED);
1082         repaint();
1083     }
1084 
1085     /**
1086      * Returns whether the <code>JInternalFrame</code> is the
1087      * currently "selected" or active frame.
1088      *
1089      * @return <code>true</code> if this internal frame is currently selected (active)
1090      * @see #setSelected
1091      */
1092     public boolean isSelected() {
1093         return isSelected;
1094     }
1095 
1096     /**
1097      * Sets an image to be displayed in the titlebar of this internal frame (usually
1098      * in the top-left corner).
1099      * Some look and feels might not support displaying an icon in the titlebar.
1100      *
1101      * This image is not the <code>desktopIcon</code> object, which
1102      * is the image displayed in the <code>JDesktop</code> when
1103      * this internal frame is iconified.
1104      *
1105      * Passing <code>null</code> to this function is valid,
1106      * but the look and feel can choose the appropriate behavior
1107      * for that situation, such as displaying no icon
1108      * or a default icon for the look and feel.
1109      *
1110      * @param icon the <code>Icon</code> to display in the title bar
1111      * @see #getFrameIcon
1112      */
1113     @BeanProperty(description
1114             = "The icon shown in the top-left corner of this internal frame.")
1115   public void setFrameIcon(Icon icon) {
1116         Icon oldIcon = frameIcon;
1117         frameIcon = icon;
1118         firePropertyChange(FRAME_ICON_PROPERTY, oldIcon, icon);
1119     }
1120 
1121     /**
1122      * Returns the image displayed in the title bar of this internal frame (usually
1123      * in the top-left corner).
1124      *
1125      * @return the <code>Icon</code> displayed in the title bar
1126      * @see #setFrameIcon
1127      */
1128     public Icon getFrameIcon()  {
1129         return frameIcon;
1130     }
1131 
1132     /**
1133       * Convenience method that moves this component to position 0 if its
1134       * parent is a <code>JLayeredPane</code>.
1135       */
1136     public void moveToFront() {
1137         if (isIcon()) {
1138             if (getDesktopIcon().getParent() instanceof JLayeredPane) {
1139                 ((JLayeredPane)getDesktopIcon().getParent()).
1140                     moveToFront(getDesktopIcon());
1141             }
1142         }
1143         else if (getParent() instanceof JLayeredPane) {
1144             ((JLayeredPane)getParent()).moveToFront(this);
1145         }
1146     }
1147 
1148     /**
1149       * Convenience method that moves this component to position -1 if its
1150       * parent is a <code>JLayeredPane</code>.
1151       */
1152     public void moveToBack() {
1153         if (isIcon()) {
1154             if (getDesktopIcon().getParent() instanceof JLayeredPane) {
1155                 ((JLayeredPane)getDesktopIcon().getParent()).
1156                     moveToBack(getDesktopIcon());
1157             }
1158         }
1159         else if (getParent() instanceof JLayeredPane) {
1160             ((JLayeredPane)getParent()).moveToBack(this);
1161         }
1162     }
1163 
1164     /**
1165      * Returns the last <code>Cursor</code> that was set by the
1166      * <code>setCursor</code> method that is not a resizable
1167      * <code>Cursor</code>.
1168      *
1169      * @return the last non-resizable <code>Cursor</code>
1170      * @since 1.6
1171      */
1172     @BeanProperty(bound = false)
1173     public Cursor getLastCursor() {
1174         return lastCursor;
1175     }
1176 
1177     /**
1178      * {@inheritDoc}
1179      * @since 1.6
1180      */
1181     public void setCursor(Cursor cursor) {
1182         if (cursor == null) {
1183             lastCursor = null;
1184             super.setCursor(cursor);
1185             return;
1186         }
1187         int type = cursor.getType();
1188         if (!(type == Cursor.SW_RESIZE_CURSOR  ||
1189               type == Cursor.SE_RESIZE_CURSOR  ||
1190               type == Cursor.NW_RESIZE_CURSOR  ||
1191               type == Cursor.NE_RESIZE_CURSOR  ||
1192               type == Cursor.N_RESIZE_CURSOR   ||
1193               type == Cursor.S_RESIZE_CURSOR   ||
1194               type == Cursor.W_RESIZE_CURSOR   ||
1195               type == Cursor.E_RESIZE_CURSOR)) {
1196             lastCursor = cursor;
1197         }
1198         super.setCursor(cursor);
1199     }
1200 
1201     /**
1202      * Convenience method for setting the layer attribute of this component.
1203      *
1204      * @param layer  an <code>Integer</code> object specifying this
1205      *          frame's desktop layer
1206      * @throws NullPointerException if {@code layer} is {@code null}
1207      * @see JLayeredPane
1208      */
1209     @BeanProperty(bound = false, expert = true, description
1210             = "Specifies what desktop layer is used.")
1211     public void setLayer(Integer layer) {
1212         if(getParent() != null && getParent() instanceof JLayeredPane) {
1213             // Normally we want to do this, as it causes the LayeredPane
1214             // to draw properly.
1215             JLayeredPane p = (JLayeredPane)getParent();
1216             p.setLayer(this, layer.intValue(), p.getPosition(this));
1217         } else {
1218              // Try to do the right thing
1219              JLayeredPane.putLayer(this, layer.intValue());
1220              if(getParent() != null)
1221                  getParent().repaint(getX(), getY(), getWidth(), getHeight());
1222         }
1223     }
1224 
1225     /**
1226      * Convenience method for setting the layer attribute of this component.
1227      * The method <code>setLayer(Integer)</code> should be used for
1228      * layer values predefined in <code>JLayeredPane</code>.
1229      * When using <code>setLayer(int)</code>, care must be taken not to
1230      * accidentally clash with those values.
1231      *
1232      * @param layer  an integer specifying this internal frame's desktop layer
1233      *
1234      * @since 1.3
1235      *
1236      * @see #setLayer(Integer)
1237      * @see JLayeredPane
1238      */
1239     @BeanProperty(bound = false, expert = true, description
1240             = "Specifies what desktop layer is used.")
1241     public void setLayer(int layer) {
1242       this.setLayer(Integer.valueOf(layer));
1243     }
1244 
1245     /**
1246      * Convenience method for getting the layer attribute of this component.
1247      *
1248      * @return  an <code>Integer</code> object specifying this
1249      *          frame's desktop layer
1250      * @see JLayeredPane
1251       */
1252     public int getLayer() {
1253         return JLayeredPane.getLayer(this);
1254     }
1255 
1256     /**
1257       * Convenience method that searches the ancestor hierarchy for a
1258       * <code>JDesktop</code> instance. If <code>JInternalFrame</code>
1259       * finds none, the <code>desktopIcon</code> tree is searched.
1260       *
1261       * @return the <code>JDesktopPane</code> this internal frame belongs to,
1262       *         or <code>null</code> if none is found
1263       */
1264     @BeanProperty(bound = false)
1265     public JDesktopPane getDesktopPane() {
1266         Container p;
1267 
1268         // Search upward for desktop
1269         p = getParent();
1270         while(p != null && !(p instanceof JDesktopPane))
1271             p = p.getParent();
1272 
1273         if(p == null) {
1274            // search its icon parent for desktop
1275            p = getDesktopIcon().getParent();
1276            while(p != null && !(p instanceof JDesktopPane))
1277                 p = p.getParent();
1278         }
1279 
1280         return (JDesktopPane)p;
1281     }
1282 
1283     /**
1284      * Sets the <code>JDesktopIcon</code> associated with this
1285      * <code>JInternalFrame</code>.
1286      *
1287      * @param d the <code>JDesktopIcon</code> to display on the desktop
1288      * @see #getDesktopIcon
1289      */
1290     @BeanProperty(description
1291             = "The icon shown when this internal frame is minimized.")
1292     public void setDesktopIcon(JDesktopIcon d) {
1293         JDesktopIcon oldValue = getDesktopIcon();
1294         desktopIcon = d;
1295         firePropertyChange("desktopIcon", oldValue, d);
1296     }
1297 
1298     /**
1299      * Returns the <code>JDesktopIcon</code> used when this
1300      * <code>JInternalFrame</code> is iconified.
1301      *
1302      * @return the <code>JDesktopIcon</code> displayed on the desktop
1303      * @see #setDesktopIcon
1304      */
1305     public JDesktopIcon getDesktopIcon() {
1306         return desktopIcon;
1307     }
1308 
1309     /**
1310      * If the <code>JInternalFrame</code> is not in maximized state, returns
1311      * <code>getBounds()</code>; otherwise, returns the bounds that the
1312      * <code>JInternalFrame</code> would be restored to.
1313      *
1314      * @return a <code>Rectangle</code> containing the bounds of this
1315      *          frame when in the normal state
1316      * @since 1.3
1317      */
1318     public Rectangle getNormalBounds() {
1319 
1320       /* we used to test (!isMaximum) here, but since this
1321          method is used by the property listener for the
1322          IS_MAXIMUM_PROPERTY, it ended up getting the wrong
1323          answer... Since normalBounds get set to null when the
1324          frame is restored, this should work better */
1325 
1326       if (normalBounds != null) {
1327         return normalBounds;
1328       } else {
1329         return getBounds();
1330       }
1331     }
1332 
1333     /**
1334      * Sets the normal bounds for this internal frame, the bounds that
1335      * this internal frame would be restored to from its maximized state.
1336      * This method is intended for use only by desktop managers.
1337      *
1338      * @param r the bounds that this internal frame should be restored to
1339      * @since 1.3
1340      */
1341     public void setNormalBounds(Rectangle r) {
1342         normalBounds = r;
1343     }
1344 
1345     /**
1346      * If this <code>JInternalFrame</code> is active,
1347      * returns the child that has focus.
1348      * Otherwise, returns <code>null</code>.
1349      *
1350      * @return the component with focus, or <code>null</code> if no children have focus
1351      * @since 1.3
1352      */
1353     public Component getFocusOwner() {
1354         if (isSelected()) {
1355             return lastFocusOwner;
1356         }
1357         return null;
1358     }
1359 
1360     /**
1361      * Returns the child component of this <code>JInternalFrame</code>
1362      * that will receive the
1363      * focus when this <code>JInternalFrame</code> is selected.
1364      * If this <code>JInternalFrame</code> is
1365      * currently selected, this method returns the same component as
1366      * the <code>getFocusOwner</code> method.
1367      * If this <code>JInternalFrame</code> is not selected,
1368      * then the child component that most recently requested focus will be
1369      * returned. If no child component has ever requested focus, then this
1370      * <code>JInternalFrame</code>'s initial focusable component is returned.
1371      * If no such
1372      * child exists, then this <code>JInternalFrame</code>'s default component
1373      * to focus is returned.
1374      *
1375      * @return the child component that will receive focus when this
1376      *         <code>JInternalFrame</code> is selected
1377      * @see #getFocusOwner
1378      * @see #isSelected
1379      * @since 1.4
1380      */
1381     @BeanProperty(bound = false)
1382     public Component getMostRecentFocusOwner() {
1383         if (isSelected()) {
1384             return getFocusOwner();
1385         }
1386 
1387         if (lastFocusOwner != null) {
1388             return lastFocusOwner;
1389         }
1390 
1391         FocusTraversalPolicy policy = getFocusTraversalPolicy();
1392         if (policy instanceof InternalFrameFocusTraversalPolicy) {
1393             return ((InternalFrameFocusTraversalPolicy)policy).
1394                 getInitialComponent(this);
1395         }
1396 
1397         Component toFocus = policy.getDefaultComponent(this);
1398         if (toFocus != null) {
1399             return toFocus;
1400         }
1401         return getContentPane();
1402     }
1403 
1404     /**
1405      * Requests the internal frame to restore focus to the
1406      * last subcomponent that had focus. This is used by the UI when
1407      * the user selected this internal frame --
1408      * for example, by clicking on the title bar.
1409      *
1410      * @since 1.3
1411      */
1412     public void restoreSubcomponentFocus() {
1413         if (isIcon()) {
1414             SwingUtilities2.compositeRequestFocus(getDesktopIcon());
1415         }
1416         else {
1417             Component component = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner();
1418             if ((component == null) || !SwingUtilities.isDescendingFrom(component, this)) {
1419                 // FocusPropertyChangeListener will eventually update
1420                 // lastFocusOwner. As focus requests are asynchronous
1421                 // lastFocusOwner may be accessed before it has been correctly
1422                 // updated. To avoid any problems, lastFocusOwner is immediately
1423                 // set, assuming the request will succeed.
1424                 setLastFocusOwner(getMostRecentFocusOwner());
1425                 if (lastFocusOwner == null) {
1426                     // Make sure focus is restored somewhere, so that
1427                     // we don't leave a focused component in another frame while
1428                     // this frame is selected.
1429                     setLastFocusOwner(getContentPane());
1430                 }
1431                 lastFocusOwner.requestFocus();
1432             }
1433         }
1434     }
1435 
1436     private void setLastFocusOwner(Component component) {
1437         lastFocusOwner = component;
1438     }
1439 
1440     /**
1441      * Moves and resizes this component.  Unlike other components,
1442      * this implementation also forces re-layout, so that frame
1443      * decorations such as the title bar are always redisplayed.
1444      *
1445      * @param x  an integer giving the component's new horizontal position
1446      *           measured in pixels from the left of its container
1447      * @param y  an integer giving the component's new vertical position,
1448      *           measured in pixels from the bottom of its container
1449      * @param width  an integer giving the component's new width in pixels
1450      * @param height an integer giving the component's new height in pixels
1451      */
1452     @SuppressWarnings("deprecation")
1453     public void reshape(int x, int y, int width, int height) {
1454         super.reshape(x, y, width, height);
1455         validate();
1456         repaint();
1457     }
1458 
1459 ///////////////////////////
1460 // Frame/Window equivalents
1461 ///////////////////////////
1462 
1463     /**
1464      * Adds the specified listener to receive internal
1465      * frame events from this internal frame.
1466      *
1467      * @param l the internal frame listener
1468      */
1469     public void addInternalFrameListener(InternalFrameListener l) {  // remind: sync ??
1470       listenerList.add(InternalFrameListener.class, l);
1471       // remind: needed?
1472       enableEvents(0);   // turn on the newEventsOnly flag in Component.
1473     }
1474 
1475     /**
1476      * Removes the specified internal frame listener so that it no longer
1477      * receives internal frame events from this internal frame.
1478      *
1479      * @param l the internal frame listener
1480      */
1481     public void removeInternalFrameListener(InternalFrameListener l) {  // remind: sync??
1482       listenerList.remove(InternalFrameListener.class, l);
1483     }
1484 
1485     /**
1486      * Returns an array of all the <code>InternalFrameListener</code>s added
1487      * to this <code>JInternalFrame</code> with
1488      * <code>addInternalFrameListener</code>.
1489      *
1490      * @return all of the <code>InternalFrameListener</code>s added or an empty
1491      *         array if no listeners have been added
1492      * @since 1.4
1493      *
1494      * @see #addInternalFrameListener
1495      */
1496     @BeanProperty(bound = false)
1497     public InternalFrameListener[] getInternalFrameListeners() {
1498         return listenerList.getListeners(InternalFrameListener.class);
1499     }
1500 
1501     // remind: name ok? all one method ok? need to be synchronized?
1502     /**
1503      * Fires an internal frame event.
1504      *
1505      * @param id  the type of the event being fired; one of the following:
1506      * <ul>
1507      * <li><code>InternalFrameEvent.INTERNAL_FRAME_OPENED</code>
1508      * <li><code>InternalFrameEvent.INTERNAL_FRAME_CLOSING</code>
1509      * <li><code>InternalFrameEvent.INTERNAL_FRAME_CLOSED</code>
1510      * <li><code>InternalFrameEvent.INTERNAL_FRAME_ICONIFIED</code>
1511      * <li><code>InternalFrameEvent.INTERNAL_FRAME_DEICONIFIED</code>
1512      * <li><code>InternalFrameEvent.INTERNAL_FRAME_ACTIVATED</code>
1513      * <li><code>InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED</code>
1514      * </ul>
1515      * If the event type is not one of the above, nothing happens.
1516      */
1517     protected void fireInternalFrameEvent(int id){
1518       Object[] listeners = listenerList.getListenerList();
1519       InternalFrameEvent e = null;
1520       for (int i = listeners.length -2; i >=0; i -= 2){
1521         if (listeners[i] == InternalFrameListener.class){
1522           if (e == null){
1523             e = new InternalFrameEvent(this, id);
1524             //      System.out.println("InternalFrameEvent: " + e.paramString());
1525           }
1526           switch(e.getID()) {
1527           case InternalFrameEvent.INTERNAL_FRAME_OPENED:
1528             ((InternalFrameListener)listeners[i+1]).internalFrameOpened(e);
1529             break;
1530           case InternalFrameEvent.INTERNAL_FRAME_CLOSING:
1531             ((InternalFrameListener)listeners[i+1]).internalFrameClosing(e);
1532             break;
1533           case InternalFrameEvent.INTERNAL_FRAME_CLOSED:
1534             ((InternalFrameListener)listeners[i+1]).internalFrameClosed(e);
1535             break;
1536           case InternalFrameEvent.INTERNAL_FRAME_ICONIFIED:
1537             ((InternalFrameListener)listeners[i+1]).internalFrameIconified(e);
1538             break;
1539           case InternalFrameEvent.INTERNAL_FRAME_DEICONIFIED:
1540             ((InternalFrameListener)listeners[i+1]).internalFrameDeiconified(e);
1541             break;
1542           case InternalFrameEvent.INTERNAL_FRAME_ACTIVATED:
1543             ((InternalFrameListener)listeners[i+1]).internalFrameActivated(e);
1544             break;
1545           case InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED:
1546             ((InternalFrameListener)listeners[i+1]).internalFrameDeactivated(e);
1547             break;
1548           default:
1549             break;
1550           }
1551         }
1552       }
1553       /* we could do it off the event, but at the moment, that's not how
1554          I'm implementing it */
1555       //      if (id == InternalFrameEvent.INTERNAL_FRAME_CLOSING) {
1556       //          doDefaultCloseAction();
1557       //      }
1558     }
1559 
1560     /**
1561      * Fires an
1562      * <code>INTERNAL_FRAME_CLOSING</code> event
1563      * and then performs the action specified by
1564      * the internal frame's default close operation.
1565      * This method is typically invoked by the
1566      * look-and-feel-implemented action handler
1567      * for the internal frame's close button.
1568      *
1569      * @since 1.3
1570      * @see #setDefaultCloseOperation
1571      * @see javax.swing.event.InternalFrameEvent#INTERNAL_FRAME_CLOSING
1572      */
1573     public void doDefaultCloseAction() {
1574         fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING);
1575         switch(defaultCloseOperation) {
1576           case DO_NOTHING_ON_CLOSE:
1577             break;
1578           case HIDE_ON_CLOSE:
1579             setVisible(false);
1580             if (isSelected())
1581                 try {
1582                     setSelected(false);
1583                 } catch (PropertyVetoException pve) {}
1584 
1585             /* should this activate the next frame? that's really
1586                desktopmanager's policy... */
1587             break;
1588           case DISPOSE_ON_CLOSE:
1589               try {
1590                 fireVetoableChange(IS_CLOSED_PROPERTY, Boolean.FALSE,
1591                                    Boolean.TRUE);
1592                 isClosed = true;
1593                 setVisible(false);
1594                 firePropertyChange(IS_CLOSED_PROPERTY, Boolean.FALSE,
1595                                    Boolean.TRUE);
1596                 dispose();
1597               } catch (PropertyVetoException pve) {}
1598               break;
1599           default:
1600               break;
1601         }
1602     }
1603 
1604     /**
1605      * Sets the operation that will happen by default when
1606      * the user initiates a "close" on this internal frame.
1607      * The possible choices are:
1608      * <br><br>
1609      * <dl>
1610      * <dt><code>DO_NOTHING_ON_CLOSE</code>
1611      * <dd> Do nothing.
1612      *      This requires the program to handle the operation
1613      *      in the <code>internalFrameClosing</code> method
1614      *      of a registered <code>InternalFrameListener</code> object.
1615      * <dt><code>HIDE_ON_CLOSE</code>
1616      * <dd> Automatically make the internal frame invisible.
1617      * <dt><code>DISPOSE_ON_CLOSE</code>
1618      * <dd> Automatically dispose of the internal frame.
1619      * </dl>
1620      * <p>
1621      * The default value is <code>DISPOSE_ON_CLOSE</code>.
1622      * Before performing the specified close operation,
1623      * the internal frame fires
1624      * an <code>INTERNAL_FRAME_CLOSING</code> event.
1625      *
1626      * @param operation one of the following constants defined in
1627      *                  <code>javax.swing.WindowConstants</code>
1628      *                  (an interface implemented by
1629      *                  <code>JInternalFrame</code>):
1630      *                  <code>DO_NOTHING_ON_CLOSE</code>,
1631      *                  <code>HIDE_ON_CLOSE</code>, or
1632      *                  <code>DISPOSE_ON_CLOSE</code>
1633      *
1634      * @see #addInternalFrameListener
1635      * @see #getDefaultCloseOperation
1636      * @see #setVisible
1637      * @see #dispose
1638      * @see InternalFrameEvent#INTERNAL_FRAME_CLOSING
1639      */
1640     public void setDefaultCloseOperation(int operation) {
1641         this.defaultCloseOperation = operation;
1642     }
1643 
1644    /**
1645     * Returns the default operation that occurs when the user
1646     * initiates a "close" on this internal frame.
1647     * @return the operation that will occur when the user closes the internal
1648     *         frame
1649     * @see #setDefaultCloseOperation
1650     */
1651     public int getDefaultCloseOperation() {
1652         return defaultCloseOperation;
1653     }
1654 
1655     /**
1656      * Causes subcomponents of this <code>JInternalFrame</code>
1657      * to be laid out at their preferred size.  Internal frames that are
1658      * iconized or maximized are first restored and then packed.  If the
1659      * internal frame is unable to be restored its state is not changed
1660      * and will not be packed.
1661      *
1662      * @see       java.awt.Window#pack
1663      */
1664     public void pack() {
1665         try {
1666             if (isIcon()) {
1667                 setIcon(false);
1668             } else if (isMaximum()) {
1669                 setMaximum(false);
1670             }
1671         } catch(PropertyVetoException e) {
1672             return;
1673         }
1674         setSize(getPreferredSize());
1675         validate();
1676     }
1677 
1678     /**
1679      * If the internal frame is not visible,
1680      * brings the internal frame to the front,
1681      * makes it visible,
1682      * and attempts to select it.
1683      * The first time the internal frame is made visible,
1684      * this method also fires an <code>INTERNAL_FRAME_OPENED</code> event.
1685      * This method does nothing if the internal frame is already visible.
1686      * Invoking this method
1687      * has the same result as invoking
1688      * <code>setVisible(true)</code>.
1689      *
1690      * @see #moveToFront
1691      * @see #setSelected
1692      * @see InternalFrameEvent#INTERNAL_FRAME_OPENED
1693      * @see #setVisible
1694      */
1695     @SuppressWarnings("deprecation")
1696     public void show() {
1697         // bug 4312922
1698         if (isVisible()) {
1699             //match the behavior of setVisible(true): do nothing
1700             return;
1701         }
1702 
1703         // bug 4149505
1704         if (!opened) {
1705           fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED);
1706           opened = true;
1707         }
1708 
1709         /* icon default visibility is false; set it to true so that it shows
1710            up when user iconifies frame */
1711         getDesktopIcon().setVisible(true);
1712 
1713         toFront();
1714         super.show();
1715 
1716         if (isIcon) {
1717             return;
1718         }
1719 
1720         if (!isSelected()) {
1721             try {
1722                 setSelected(true);
1723             } catch (PropertyVetoException pve) {}
1724         }
1725     }
1726 
1727     @SuppressWarnings("deprecation")
1728     public void hide() {
1729         if (isIcon()) {
1730             getDesktopIcon().setVisible(false);
1731         }
1732         super.hide();
1733     }
1734 
1735     /**
1736      * Makes this internal frame
1737      * invisible, unselected, and closed.
1738      * If the frame is not already closed,
1739      * this method fires an
1740      * <code>INTERNAL_FRAME_CLOSED</code> event.
1741      * The results of invoking this method are similar to
1742      * <code>setClosed(true)</code>,
1743      * but <code>dispose</code> always succeeds in closing
1744      * the internal frame and does not fire
1745      * an <code>INTERNAL_FRAME_CLOSING</code> event.
1746      *
1747      * @see javax.swing.event.InternalFrameEvent#INTERNAL_FRAME_CLOSED
1748      * @see #setVisible
1749      * @see #setSelected
1750      * @see #setClosed
1751      */
1752     public void dispose() {
1753         if (isVisible()) {
1754             setVisible(false);
1755         }
1756         if (isSelected()) {
1757             try {
1758                 setSelected(false);
1759             } catch (PropertyVetoException pve) {}
1760         }
1761         if (!isClosed) {
1762           firePropertyChange(IS_CLOSED_PROPERTY, Boolean.FALSE, Boolean.TRUE);
1763           isClosed = true;
1764         }
1765         fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED);
1766     }
1767 
1768     /**
1769      * Brings this internal frame to the front.
1770      * Places this internal frame  at the top of the stacking order
1771      * and makes the corresponding adjustment to other visible internal
1772      * frames.
1773      *
1774      * @see       java.awt.Window#toFront
1775      * @see       #moveToFront
1776      */
1777     public void toFront() {
1778         moveToFront();
1779     }
1780 
1781     /**
1782      * Sends this internal frame to the back.
1783      * Places this internal frame at the bottom of the stacking order
1784      * and makes the corresponding adjustment to other visible
1785      * internal frames.
1786      *
1787      * @see       java.awt.Window#toBack
1788      * @see       #moveToBack
1789      */
1790     public void toBack() {
1791         moveToBack();
1792     }
1793 
1794     /**
1795      * Does nothing because <code>JInternalFrame</code>s must always be roots of a focus
1796      * traversal cycle.
1797      *
1798      * @param focusCycleRoot this value is ignored
1799      * @see #isFocusCycleRoot
1800      * @see java.awt.Container#setFocusTraversalPolicy
1801      * @see java.awt.Container#getFocusTraversalPolicy
1802      * @since 1.4
1803      */
1804     public final void setFocusCycleRoot(boolean focusCycleRoot) {
1805     }
1806 
1807     /**
1808      * Always returns <code>true</code> because all <code>JInternalFrame</code>s must be
1809      * roots of a focus traversal cycle.
1810      *
1811      * @return <code>true</code>
1812      * @see #setFocusCycleRoot
1813      * @see java.awt.Container#setFocusTraversalPolicy
1814      * @see java.awt.Container#getFocusTraversalPolicy
1815      * @since 1.4
1816      */
1817     public final boolean isFocusCycleRoot() {
1818         return true;
1819     }
1820 
1821     /**
1822      * Always returns <code>null</code> because <code>JInternalFrame</code>s
1823      * must always be roots of a focus
1824      * traversal cycle.
1825      *
1826      * @return <code>null</code>
1827      * @see java.awt.Container#isFocusCycleRoot()
1828      * @since 1.4
1829      */
1830     @BeanProperty(bound = false)
1831     public final Container getFocusCycleRootAncestor() {
1832         return null;
1833     }
1834 
1835     /**
1836      * Gets the warning string that is displayed with this internal frame.
1837      * Since an internal frame is always secure (since it's fully
1838      * contained within a window that might need a warning string)
1839      * this method always returns <code>null</code>.
1840      * @return    <code>null</code>
1841      * @see       java.awt.Window#getWarningString
1842      */
1843     @BeanProperty(bound = false)
1844     public final String getWarningString() {
1845         return null;
1846     }
1847 
1848     /**
1849      * See <code>readObject</code> and <code>writeObject</code>
1850      * in <code>JComponent</code> for more
1851      * information about serialization in Swing.
1852      */
1853     private void writeObject(ObjectOutputStream s) throws IOException {
1854         s.defaultWriteObject();
1855         if (getUIClassID().equals(uiClassID)) {
1856             byte count = JComponent.getWriteObjCounter(this);
1857             JComponent.setWriteObjCounter(this, --count);
1858             if (count == 0 && ui != null) {
1859                 boolean old = isRootPaneCheckingEnabled();
1860                 try {
1861                     setRootPaneCheckingEnabled(false);
1862                     ui.installUI(this);
1863                 } finally {
1864                     setRootPaneCheckingEnabled(old);
1865                 }
1866             }
1867         }
1868     }
1869 
1870     /* Called from the JComponent's EnableSerializationFocusListener to
1871      * do any Swing-specific pre-serialization configuration.
1872      */
1873     void compWriteObjectNotify() {
1874       // need to disable rootpane checking for InternalFrame: 4172083
1875       boolean old = isRootPaneCheckingEnabled();
1876       try {
1877         setRootPaneCheckingEnabled(false);
1878         super.compWriteObjectNotify();
1879       }
1880       finally {
1881         setRootPaneCheckingEnabled(old);
1882       }
1883     }
1884 
1885     /**
1886      * Returns a string representation of this <code>JInternalFrame</code>.
1887      * This method
1888      * is intended to be used only for debugging purposes, and the
1889      * content and format of the returned string may vary between
1890      * implementations. The returned string may be empty but may not
1891      * be <code>null</code>.
1892      *
1893      * @return  a string representation of this <code>JInternalFrame</code>
1894      */
1895     protected String paramString() {
1896         String rootPaneString = (rootPane != null ?
1897                                  rootPane.toString() : "");
1898         String rootPaneCheckingEnabledString = (rootPaneCheckingEnabled ?
1899                                                 "true" : "false");
1900         String closableString = (closable ? "true" : "false");
1901         String isClosedString = (isClosed ? "true" : "false");
1902         String maximizableString = (maximizable ? "true" : "false");
1903         String isMaximumString = (isMaximum ? "true" : "false");
1904         String iconableString = (iconable ? "true" : "false");
1905         String isIconString = (isIcon ? "true" : "false");
1906         String resizableString = (resizable ? "true" : "false");
1907         String isSelectedString = (isSelected ? "true" : "false");
1908         String frameIconString = (frameIcon != null ?
1909                                   frameIcon.toString() : "");
1910         String titleString = (title != null ?
1911                               title : "");
1912         String desktopIconString = (desktopIcon != null ?
1913                                     desktopIcon.toString() : "");
1914         String openedString = (opened ? "true" : "false");
1915         String defaultCloseOperationString;
1916         if (defaultCloseOperation == HIDE_ON_CLOSE) {
1917             defaultCloseOperationString = "HIDE_ON_CLOSE";
1918         } else if (defaultCloseOperation == DISPOSE_ON_CLOSE) {
1919             defaultCloseOperationString = "DISPOSE_ON_CLOSE";
1920         } else if (defaultCloseOperation == DO_NOTHING_ON_CLOSE) {
1921             defaultCloseOperationString = "DO_NOTHING_ON_CLOSE";
1922         } else defaultCloseOperationString = "";
1923 
1924         return super.paramString() +
1925         ",closable=" + closableString +
1926         ",defaultCloseOperation=" + defaultCloseOperationString +
1927         ",desktopIcon=" + desktopIconString +
1928         ",frameIcon=" + frameIconString +
1929         ",iconable=" + iconableString +
1930         ",isClosed=" + isClosedString +
1931         ",isIcon=" + isIconString +
1932         ",isMaximum=" + isMaximumString +
1933         ",isSelected=" + isSelectedString +
1934         ",maximizable=" + maximizableString +
1935         ",opened=" + openedString +
1936         ",resizable=" + resizableString +
1937         ",rootPane=" + rootPaneString +
1938         ",rootPaneCheckingEnabled=" + rootPaneCheckingEnabledString +
1939         ",title=" + titleString;
1940     }
1941 
1942     // ======= begin optimized frame dragging defence code ==============
1943 
1944     boolean isDragging = false;
1945     boolean danger = false;
1946 
1947     /**
1948      * Overridden to allow optimized painting when the
1949      * internal frame is being dragged.
1950      */
1951     protected void paintComponent(Graphics g) {
1952       if (isDragging) {
1953         //         System.out.println("ouch");
1954          danger = true;
1955       }
1956 
1957       super.paintComponent(g);
1958    }
1959 
1960     // ======= end optimized frame dragging defence code ==============
1961 
1962 /////////////////
1963 // Accessibility support
1964 ////////////////
1965 
1966     /**
1967      * Gets the <code>AccessibleContext</code> associated with this
1968      * <code>JInternalFrame</code>.
1969      * For internal frames, the <code>AccessibleContext</code>
1970      * takes the form of an
1971      * <code>AccessibleJInternalFrame</code> object.
1972      * A new <code>AccessibleJInternalFrame</code> instance is created if necessary.
1973      *
1974      * @return an <code>AccessibleJInternalFrame</code> that serves as the
1975      *         <code>AccessibleContext</code> of this
1976      *         <code>JInternalFrame</code>
1977      * @see AccessibleJInternalFrame
1978      */
1979     @BeanProperty(bound = false)
1980     public AccessibleContext getAccessibleContext() {
1981         if (accessibleContext == null) {
1982             accessibleContext = new AccessibleJInternalFrame();
1983         }
1984         return accessibleContext;
1985     }
1986 
1987     /**
1988      * This class implements accessibility support for the
1989      * <code>JInternalFrame</code> class.  It provides an implementation of the
1990      * Java Accessibility API appropriate to internal frame user-interface
1991      * elements.
1992      * <p>
1993      * <strong>Warning:</strong>
1994      * Serialized objects of this class will not be compatible with
1995      * future Swing releases. The current serialization support is
1996      * appropriate for short term storage or RMI between applications running
1997      * the same version of Swing.  As of 1.4, support for long term storage
1998      * of all JavaBeans&trade;
1999      * has been added to the <code>java.beans</code> package.
2000      * Please see {@link java.beans.XMLEncoder}.
2001      */
2002     @SuppressWarnings("serial") // Same-version serialization only
2003     protected class AccessibleJInternalFrame extends AccessibleJComponent
2004         implements AccessibleValue {
2005 
2006         /**
2007          * Get the accessible name of this object.
2008          *
2009          * @return the localized name of the object -- can be <code>null</code> if this
2010          * object does not have a name
2011          * @see #setAccessibleName
2012          */
2013         public String getAccessibleName() {
2014             String name = accessibleName;
2015 
2016             if (name == null) {
2017                 name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY);
2018             }
2019             if (name == null) {
2020                 name = getTitle();
2021             }
2022             return name;
2023         }
2024 
2025         /**
2026          * Get the role of this object.
2027          *
2028          * @return an instance of AccessibleRole describing the role of the
2029          * object
2030          * @see AccessibleRole
2031          */
2032         public AccessibleRole getAccessibleRole() {
2033             return AccessibleRole.INTERNAL_FRAME;
2034         }
2035 
2036         /**
2037          * Gets the AccessibleValue associated with this object.  In the
2038          * implementation of the Java Accessibility API for this class,
2039          * returns this object, which is responsible for implementing the
2040          * <code>AccessibleValue</code> interface on behalf of itself.
2041          *
2042          * @return this object
2043          */
2044         public AccessibleValue getAccessibleValue() {
2045             return this;
2046         }
2047 
2048 
2049         //
2050         // AccessibleValue methods
2051         //
2052 
2053         /**
2054          * Get the value of this object as a Number.
2055          *
2056          * @return value of the object -- can be <code>null</code> if this object does not
2057          * have a value
2058          */
2059         public Number getCurrentAccessibleValue() {
2060             return Integer.valueOf(getLayer());
2061         }
2062 
2063         /**
2064          * Set the value of this object as a Number.
2065          *
2066          * @return <code>true</code> if the value was set
2067          */
2068         public boolean setCurrentAccessibleValue(Number n) {
2069             // TIGER - 4422535
2070             if (n == null) {
2071                 return false;
2072             }
2073             setLayer(Integer.valueOf(n.intValue()));
2074             return true;
2075         }
2076 
2077         /**
2078          * Get the minimum value of this object as a Number.
2079          *
2080          * @return Minimum value of the object; <code>null</code> if this object does not
2081          * have a minimum value
2082          */
2083         public Number getMinimumAccessibleValue() {
2084             return Integer.MIN_VALUE;
2085         }
2086 
2087         /**
2088          * Get the maximum value of this object as a Number.
2089          *
2090          * @return Maximum value of the object; <code>null</code> if this object does not
2091          * have a maximum value
2092          */
2093         public Number getMaximumAccessibleValue() {
2094             return Integer.MAX_VALUE;
2095         }
2096 
2097     } // AccessibleJInternalFrame
2098 
2099     /**
2100      * This component represents an iconified version of a
2101      * <code>JInternalFrame</code>.
2102      * This API should NOT BE USED by Swing applications, as it will go
2103      * away in future versions of Swing as its functionality is moved into
2104      * <code>JInternalFrame</code>.  This class is public only so that
2105      * UI objects can display a desktop icon.  If an application
2106      * wants to display a desktop icon, it should create a
2107      * <code>JInternalFrame</code> instance and iconify it.
2108      * <p>
2109      * <strong>Warning:</strong>
2110      * Serialized objects of this class will not be compatible with
2111      * future Swing releases. The current serialization support is
2112      * appropriate for short term storage or RMI between applications running
2113      * the same version of Swing.  As of 1.4, support for long term storage
2114      * of all JavaBeans&trade;
2115      * has been added to the <code>java.beans</code> package.
2116      * Please see {@link java.beans.XMLEncoder}.
2117      *
2118      * @author David Kloba
2119      */
2120     @SuppressWarnings("serial") // Same-version serialization only
2121     static public class JDesktopIcon extends JComponent implements Accessible
2122     {
2123         JInternalFrame internalFrame;
2124 
2125         /**
2126          * Creates an icon for an internal frame.
2127          *
2128          * @param f  the <code>JInternalFrame</code>
2129          *              for which the icon is created
2130          */
2131         public JDesktopIcon(JInternalFrame f) {
2132             setVisible(false);
2133             setInternalFrame(f);
2134             updateUI();
2135         }
2136 
2137         /**
2138          * Returns the look-and-feel object that renders this component.
2139          *
2140          * @return the <code>DesktopIconUI</code> object that renders
2141          *              this component
2142          */
2143         public DesktopIconUI getUI() {
2144             return (DesktopIconUI)ui;
2145         }
2146 
2147         /**
2148          * Sets the look-and-feel object that renders this component.
2149          *
2150          * @param ui  the <code>DesktopIconUI</code> look-and-feel object
2151          * @see UIDefaults#getUI
2152          */
2153         public void setUI(DesktopIconUI ui) {
2154             super.setUI(ui);
2155         }
2156 
2157         /**
2158          * Returns the <code>JInternalFrame</code> that this
2159          * <code>DesktopIcon</code> is associated with.
2160          *
2161          * @return the <code>JInternalFrame</code> with which this icon
2162          *              is associated
2163          */
2164         public JInternalFrame getInternalFrame() {
2165             return internalFrame;
2166         }
2167 
2168         /**
2169          * Sets the <code>JInternalFrame</code> with which this
2170          * <code>DesktopIcon</code> is associated.
2171          *
2172          * @param f  the <code>JInternalFrame</code> with which this icon
2173          *              is associated
2174          */
2175         public void setInternalFrame(JInternalFrame f) {
2176             internalFrame = f;
2177         }
2178 
2179         /**
2180          * Convenience method to ask the icon for the <code>Desktop</code>
2181          * object it belongs to.
2182          *
2183          * @return the <code>JDesktopPane</code> that contains this
2184          *           icon's internal frame, or <code>null</code> if none found
2185          */
2186         public JDesktopPane getDesktopPane() {
2187             if(getInternalFrame() != null)
2188                 return getInternalFrame().getDesktopPane();
2189             return null;
2190         }
2191 
2192         /**
2193          * Notification from the <code>UIManager</code> that the look and feel
2194          * has changed.
2195          * Replaces the current UI object with the latest version from the
2196          * <code>UIManager</code>.
2197          *
2198          * @see JComponent#updateUI
2199          */
2200         public void updateUI() {
2201             boolean hadUI = (ui != null);
2202             setUI((DesktopIconUI)UIManager.getUI(this));
2203             invalidate();
2204 
2205             Dimension r = getPreferredSize();
2206             setSize(r.width, r.height);
2207 
2208 
2209             if (internalFrame != null && internalFrame.getUI() != null) {  // don't do this if UI not created yet
2210                 SwingUtilities.updateComponentTreeUI(internalFrame);
2211             }
2212         }
2213 
2214         /* This method is called if updateUI was called on the associated
2215          * JInternalFrame.  It's necessary to avoid infinite recursion.
2216          */
2217         void updateUIWhenHidden() {
2218             /* Update this UI and any associated internal frame */
2219             setUI((DesktopIconUI)UIManager.getUI(this));
2220 
2221             Dimension r = getPreferredSize();
2222             setSize(r.width, r.height);
2223 
2224             invalidate();
2225             Component[] children = getComponents();
2226             if (children != null) {
2227                 for (Component child : children) {
2228                     SwingUtilities.updateComponentTreeUI(child);
2229                 }
2230             }
2231         }
2232 
2233         /**
2234          * Returns the name of the look-and-feel
2235          * class that renders this component.
2236          *
2237          * @return the string "DesktopIconUI"
2238          * @see JComponent#getUIClassID
2239          * @see UIDefaults#getUI
2240          */
2241         public String getUIClassID() {
2242             return "DesktopIconUI";
2243         }
2244         ////////////////
2245         // Serialization support
2246         ////////////////
2247         private void writeObject(ObjectOutputStream s) throws IOException {
2248             s.defaultWriteObject();
2249             if (getUIClassID().equals("DesktopIconUI")) {
2250                 byte count = JComponent.getWriteObjCounter(this);
2251                 JComponent.setWriteObjCounter(this, --count);
2252                 if (count == 0 && ui != null) {
2253                     ui.installUI(this);
2254                 }
2255             }
2256         }
2257 
2258        /////////////////
2259        // Accessibility support
2260        ////////////////
2261 
2262         /**
2263          * Gets the AccessibleContext associated with this JDesktopIcon.
2264          * For desktop icons, the AccessibleContext takes the form of an
2265          * AccessibleJDesktopIcon.
2266          * A new AccessibleJDesktopIcon instance is created if necessary.
2267          *
2268          * @return an AccessibleJDesktopIcon that serves as the
2269          *         AccessibleContext of this JDesktopIcon
2270          */
2271         public AccessibleContext getAccessibleContext() {
2272             if (accessibleContext == null) {
2273                 accessibleContext = new AccessibleJDesktopIcon();
2274             }
2275             return accessibleContext;
2276         }
2277 
2278         /**
2279          * This class implements accessibility support for the
2280          * <code>JInternalFrame.JDesktopIcon</code> class.  It provides an
2281          * implementation of the Java Accessibility API appropriate to
2282          * desktop icon user-interface elements.
2283          * <p>
2284          * <strong>Warning:</strong>
2285          * Serialized objects of this class will not be compatible with
2286          * future Swing releases. The current serialization support is
2287          * appropriate for short term storage or RMI between applications running
2288          * the same version of Swing.  As of 1.4, support for long term storage
2289          * of all JavaBeans&trade;
2290          * has been added to the <code>java.beans</code> package.
2291          * Please see {@link java.beans.XMLEncoder}.
2292          */
2293         @SuppressWarnings("serial") // Same-version serialization only
2294         protected class AccessibleJDesktopIcon extends AccessibleJComponent
2295             implements AccessibleValue {
2296 
2297             /**
2298              * Gets the role of this object.
2299              *
2300              * @return an instance of AccessibleRole describing the role of the
2301              * object
2302              * @see AccessibleRole
2303              */
2304             public AccessibleRole getAccessibleRole() {
2305                 return AccessibleRole.DESKTOP_ICON;
2306             }
2307 
2308             /**
2309              * Gets the AccessibleValue associated with this object.  In the
2310              * implementation of the Java Accessibility API for this class,
2311              * returns this object, which is responsible for implementing the
2312              * <code>AccessibleValue</code> interface on behalf of itself.
2313              *
2314              * @return this object
2315              */
2316             public AccessibleValue getAccessibleValue() {
2317                 return this;
2318             }
2319 
2320             //
2321             // AccessibleValue methods
2322             //
2323 
2324             /**
2325              * Gets the value of this object as a <code>Number</code>.
2326              *
2327              * @return value of the object -- can be <code>null</code> if this object does not
2328              * have a value
2329              */
2330             public Number getCurrentAccessibleValue() {
2331                 AccessibleContext a = JDesktopIcon.this.getInternalFrame().getAccessibleContext();
2332                 AccessibleValue v = a.getAccessibleValue();
2333                 if (v != null) {
2334                     return v.getCurrentAccessibleValue();
2335                 } else {
2336                     return null;
2337                 }
2338             }
2339 
2340             /**
2341              * Sets the value of this object as a <code>Number</code>.
2342              *
2343              * @return <code>true</code> if the value was set
2344              */
2345             public boolean setCurrentAccessibleValue(Number n) {
2346                 // TIGER - 4422535
2347                 if (n == null) {
2348                     return false;
2349                 }
2350                 AccessibleContext a = JDesktopIcon.this.getInternalFrame().getAccessibleContext();
2351                 AccessibleValue v = a.getAccessibleValue();
2352                 if (v != null) {
2353                     return v.setCurrentAccessibleValue(n);
2354                 } else {
2355                     return false;
2356                 }
2357             }
2358 
2359             /**
2360              * Gets the minimum value of this object as a <code>Number</code>.
2361              *
2362              * @return minimum value of the object; <code>null</code> if this object does not
2363              * have a minimum value
2364              */
2365             public Number getMinimumAccessibleValue() {
2366                 AccessibleContext a = JDesktopIcon.this.getInternalFrame().getAccessibleContext();
2367                 if (a instanceof AccessibleValue) {
2368                     return ((AccessibleValue)a).getMinimumAccessibleValue();
2369                 } else {
2370                     return null;
2371                 }
2372             }
2373 
2374             /**
2375              * Gets the maximum value of this object as a <code>Number</code>.
2376              *
2377              * @return maximum value of the object; <code>null</code> if this object does not
2378              * have a maximum value
2379              */
2380             public Number getMaximumAccessibleValue() {
2381                 AccessibleContext a = JDesktopIcon.this.getInternalFrame().getAccessibleContext();
2382                 if (a instanceof AccessibleValue) {
2383                     return ((AccessibleValue)a).getMaximumAccessibleValue();
2384                 } else {
2385                     return null;
2386                 }
2387             }
2388 
2389         } // AccessibleJDesktopIcon
2390     }
2391 }