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