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