/* * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javax.swing; import java.awt.*; import java.beans.*; import javax.swing.event.InternalFrameEvent; import javax.swing.event.InternalFrameListener; import javax.swing.plaf.*; import javax.accessibility.*; import java.io.ObjectOutputStream; import java.io.IOException; import sun.awt.AppContext; import sun.swing.SwingUtilities2; /** * A lightweight object that provides many of the features of * a native frame, including dragging, closing, becoming an icon, * resizing, title display, and support for a menu bar. * For task-oriented documentation and examples of using internal frames, * see <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/internalframe.html" target="_top">How to Use Internal Frames</a>, * a section in <em>The Java Tutorial</em>. * * <p> * * Generally, * you add <code>JInternalFrame</code>s to a <code>JDesktopPane</code>. The UI * delegates the look-and-feel-specific actions to the * <code>DesktopManager</code> * object maintained by the <code>JDesktopPane</code>. * <p> * The <code>JInternalFrame</code> content pane * is where you add child components. * As a convenience, the {@code add}, {@code remove}, and {@code setLayout} * methods of this class are overridden, so that they delegate calls * to the corresponding methods of the {@code ContentPane}. * For example, you can add a child component to an internal frame as follows: * <pre> * internalFrame.add(child); * </pre> * And the child will be added to the contentPane. * The content pane is actually managed by an instance of * <code>JRootPane</code>, * which also manages a layout pane, glass pane, and * optional menu bar for the internal frame. Please see the * <code>JRootPane</code> * documentation for a complete description of these components. * Refer to {@link javax.swing.RootPaneContainer} * for details on adding, removing and setting the <code>LayoutManager</code> * of a <code>JInternalFrame</code>. * <p> * <strong>Warning:</strong> Swing is not thread safe. For more * information see <a * href="package-summary.html#threading">Swing's Threading * Policy</a>. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans™ * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @see InternalFrameEvent * @see JDesktopPane * @see DesktopManager * @see JInternalFrame.JDesktopIcon * @see JRootPane * @see javax.swing.RootPaneContainer * * @author David Kloba * @author Rich Schiavi * @since 1.2 */ @JavaBean(defaultProperty = "JMenuBar", description = "A frame container which is contained within another window.") @SwingContainer(delegate = "getContentPane") @SuppressWarnings("serial") // Same-version serialization only public class JInternalFrame extends JComponent implements Accessible, WindowConstants, RootPaneContainer { /** * @see #getUIClassID * @see #readObject */ private static final String uiClassID = "InternalFrameUI"; /** * The <code>JRootPane</code> instance that manages the * content pane * and optional menu bar for this internal frame, as well as the * glass pane. * * @see JRootPane * @see RootPaneContainer */ protected JRootPane rootPane; /** * If true then calls to <code>add</code> and <code>setLayout</code> * will be forwarded to the <code>contentPane</code>. This is initially * false, but is set to true when the <code>JInternalFrame</code> is * constructed. * * @see #isRootPaneCheckingEnabled * @see #setRootPaneCheckingEnabled * @see javax.swing.RootPaneContainer */ protected boolean rootPaneCheckingEnabled = false; /** The frame can be closed. */ protected boolean closable; /** The frame has been closed. */ protected boolean isClosed; /** The frame can be expanded to the size of the desktop pane. */ protected boolean maximizable; /** * The frame has been expanded to its maximum size. * @see #maximizable */ protected boolean isMaximum; /** * The frame can "iconified" (shrunk down and displayed as * an icon-image). * @see JInternalFrame.JDesktopIcon * @see #setIconifiable */ protected boolean iconable; /** * The frame has been iconified. * @see #isIcon() */ protected boolean isIcon; /** The frame's size can be changed. */ protected boolean resizable; /** The frame is currently selected. */ protected boolean isSelected; /** The icon shown in the top-left corner of this internal frame. */ protected Icon frameIcon; /** The title displayed in this internal frame's title bar. */ protected String title; /** * The icon that is displayed when this internal frame is iconified. * @see #iconable */ protected JDesktopIcon desktopIcon; private Cursor lastCursor; private boolean opened; private Rectangle normalBounds = null; private int defaultCloseOperation = DISPOSE_ON_CLOSE; /** * Contains the Component that focus is to go when * <code>restoreSubcomponentFocus</code> is invoked, that is, * <code>restoreSubcomponentFocus</code> sets this to the value returned * from <code>getMostRecentFocusOwner</code>. */ private Component lastFocusOwner; /** Bound property name. */ public static final String CONTENT_PANE_PROPERTY = "contentPane"; /** Bound property name. */ public static final String MENU_BAR_PROPERTY = "JMenuBar"; /** Bound property name. */ public static final String TITLE_PROPERTY = "title"; /** Bound property name. */ public static final String LAYERED_PANE_PROPERTY = "layeredPane"; /** Bound property name. */ public static final String ROOT_PANE_PROPERTY = "rootPane"; /** Bound property name. */ public static final String GLASS_PANE_PROPERTY = "glassPane"; /** Bound property name. */ public static final String FRAME_ICON_PROPERTY = "frameIcon"; /** * Constrained property name indicated that this frame has * selected status. */ public static final String IS_SELECTED_PROPERTY = "selected"; /** Constrained property name indicating that the internal frame is closed. */ public static final String IS_CLOSED_PROPERTY = "closed"; /** Constrained property name indicating that the internal frame is maximized. */ public static final String IS_MAXIMUM_PROPERTY = "maximum"; /** Constrained property name indicating that the internal frame is iconified. */ public static final String IS_ICON_PROPERTY = "icon"; private static final Object PROPERTY_CHANGE_LISTENER_KEY = new StringBuilder("InternalFramePropertyChangeListener"); private static void addPropertyChangeListenerIfNecessary() { if (AppContext.getAppContext().get(PROPERTY_CHANGE_LISTENER_KEY) == null) { PropertyChangeListener focusListener = new FocusPropertyChangeListener(); AppContext.getAppContext().put(PROPERTY_CHANGE_LISTENER_KEY, focusListener); KeyboardFocusManager.getCurrentKeyboardFocusManager(). addPropertyChangeListener(focusListener); } } private static class FocusPropertyChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent e) { if (e.getPropertyName() == "permanentFocusOwner") { updateLastFocusOwner((Component)e.getNewValue()); } } } private static void updateLastFocusOwner(Component component) { if (component != null) { Component parent = component; while (parent != null && !(parent instanceof Window)) { if (parent instanceof JInternalFrame) { // Update lastFocusOwner for parent. ((JInternalFrame)parent).setLastFocusOwner(component); } parent = parent.getParent(); } } } /** * Creates a non-resizable, non-closable, non-maximizable, * non-iconifiable <code>JInternalFrame</code> with no title. */ public JInternalFrame() { this("", false, false, false, false); } /** * Creates a non-resizable, non-closable, non-maximizable, * non-iconifiable <code>JInternalFrame</code> with the specified title. * Note that passing in a <code>null</code> <code>title</code> results in * unspecified behavior and possibly an exception. * * @param title the non-<code>null</code> <code>String</code> * to display in the title bar */ public JInternalFrame(String title) { this(title, false, false, false, false); } /** * Creates a non-closable, non-maximizable, non-iconifiable * <code>JInternalFrame</code> with the specified title * and resizability. * * @param title the <code>String</code> to display in the title bar * @param resizable if <code>true</code>, the internal frame can be resized */ public JInternalFrame(String title, boolean resizable) { this(title, resizable, false, false, false); } /** * Creates a non-maximizable, non-iconifiable <code>JInternalFrame</code> * with the specified title, resizability, and * closability. * * @param title the <code>String</code> to display in the title bar * @param resizable if <code>true</code>, the internal frame can be resized * @param closable if <code>true</code>, the internal frame can be closed */ public JInternalFrame(String title, boolean resizable, boolean closable) { this(title, resizable, closable, false, false); } /** * Creates a non-iconifiable <code>JInternalFrame</code> * with the specified title, * resizability, closability, and maximizability. * * @param title the <code>String</code> to display in the title bar * @param resizable if <code>true</code>, the internal frame can be resized * @param closable if <code>true</code>, the internal frame can be closed * @param maximizable if <code>true</code>, the internal frame can be maximized */ public JInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable) { this(title, resizable, closable, maximizable, false); } /** * Creates a <code>JInternalFrame</code> with the specified title, * resizability, closability, maximizability, and iconifiability. * All <code>JInternalFrame</code> constructors use this one. * * @param title the <code>String</code> to display in the title bar * @param resizable if <code>true</code>, the internal frame can be resized * @param closable if <code>true</code>, the internal frame can be closed * @param maximizable if <code>true</code>, the internal frame can be maximized * @param iconifiable if <code>true</code>, the internal frame can be iconified */ public JInternalFrame(String title, boolean resizable, boolean closable, boolean maximizable, boolean iconifiable) { setRootPane(createRootPane()); setLayout(new BorderLayout()); this.title = title; this.resizable = resizable; this.closable = closable; this.maximizable = maximizable; isMaximum = false; this.iconable = iconifiable; isIcon = false; setVisible(false); setRootPaneCheckingEnabled(true); desktopIcon = new JDesktopIcon(this); updateUI(); sun.awt.SunToolkit.checkAndSetPolicy(this); addPropertyChangeListenerIfNecessary(); } /** * Called by the constructor to set up the <code>JRootPane</code>. * @return a new <code>JRootPane</code> * @see JRootPane */ protected JRootPane createRootPane() { return new JRootPane(); } /** * Returns the look-and-feel object that renders this component. * * @return the <code>InternalFrameUI</code> object that renders * this component */ public InternalFrameUI getUI() { return (InternalFrameUI)ui; } /** * Sets the UI delegate for this <code>JInternalFrame</code>. * @param ui the UI delegate */ @BeanProperty(hidden = true, visualUpdate = true, description = "The UI object that implements the Component's LookAndFeel.") public void setUI(InternalFrameUI ui) { boolean checkingEnabled = isRootPaneCheckingEnabled(); try { setRootPaneCheckingEnabled(false); super.setUI(ui); } finally { setRootPaneCheckingEnabled(checkingEnabled); } } /** * Notification from the <code>UIManager</code> that the look and feel * has changed. * Replaces the current UI object with the latest version from the * <code>UIManager</code>. * * @see JComponent#updateUI */ public void updateUI() { setUI((InternalFrameUI)UIManager.getUI(this)); invalidate(); if (desktopIcon != null) { desktopIcon.updateUIWhenHidden(); } } /* This method is called if <code>updateUI</code> was called * on the associated * JDesktopIcon. It's necessary to avoid infinite recursion. */ void updateUIWhenHidden() { setUI((InternalFrameUI)UIManager.getUI(this)); invalidate(); Component[] children = getComponents(); if (children != null) { for (Component child : children) { SwingUtilities.updateComponentTreeUI(child); } } } /** * Returns the name of the look-and-feel * class that renders this component. * * @return the string "InternalFrameUI" * * @see JComponent#getUIClassID * @see UIDefaults#getUI */ @BeanProperty(bound = false, description = "UIClassID") public String getUIClassID() { return uiClassID; } /** * Returns whether calls to <code>add</code> and * <code>setLayout</code> are forwarded to the <code>contentPane</code>. * * @return true if <code>add</code> and <code>setLayout</code> * are forwarded; false otherwise * * @see #addImpl * @see #setLayout * @see #setRootPaneCheckingEnabled * @see javax.swing.RootPaneContainer */ protected boolean isRootPaneCheckingEnabled() { return rootPaneCheckingEnabled; } /** * Sets whether calls to <code>add</code> and * <code>setLayout</code> are forwarded to the <code>contentPane</code>. * * @param enabled true if <code>add</code> and <code>setLayout</code> * are forwarded, false if they should operate directly on the * <code>JInternalFrame</code>. * * @see #addImpl * @see #setLayout * @see #isRootPaneCheckingEnabled * @see javax.swing.RootPaneContainer */ @BeanProperty(hidden = true, description = "Whether the add and setLayout methods are forwarded") protected void setRootPaneCheckingEnabled(boolean enabled) { rootPaneCheckingEnabled = enabled; } /** * Adds the specified child <code>Component</code>. * This method is overridden to conditionally forward calls to the * <code>contentPane</code>. * By default, children are added to the <code>contentPane</code> instead * of the frame, refer to {@link javax.swing.RootPaneContainer} for * details. * * @param comp the component to be enhanced * @param constraints the constraints to be respected * @param index the index * @exception IllegalArgumentException if <code>index</code> is invalid * @exception IllegalArgumentException if adding the container's parent * to itself * @exception IllegalArgumentException if adding a window to a container * * @see #setRootPaneCheckingEnabled * @see javax.swing.RootPaneContainer */ protected void addImpl(Component comp, Object constraints, int index) { if(isRootPaneCheckingEnabled()) { getContentPane().add(comp, constraints, index); } else { super.addImpl(comp, constraints, index); } } /** * Removes the specified component from the container. If * <code>comp</code> is not a child of the <code>JInternalFrame</code> * this will forward the call to the <code>contentPane</code>. * * @param comp the component to be removed * @throws NullPointerException if <code>comp</code> is null * @see #add * @see javax.swing.RootPaneContainer */ public void remove(Component comp) { int oldCount = getComponentCount(); super.remove(comp); if (oldCount == getComponentCount()) { getContentPane().remove(comp); } } /** * Ensures that, by default, the layout of this component cannot be set. * Overridden to conditionally forward the call to the * <code>contentPane</code>. * Refer to {@link javax.swing.RootPaneContainer} for * more information. * * @param manager the <code>LayoutManager</code> * @see #setRootPaneCheckingEnabled */ public void setLayout(LayoutManager manager) { if(isRootPaneCheckingEnabled()) { getContentPane().setLayout(manager); } else { super.setLayout(manager); } } ////////////////////////////////////////////////////////////////////////// /// Property Methods ////////////////////////////////////////////////////////////////////////// /** * Returns the current <code>JMenuBar</code> for this * <code>JInternalFrame</code>, or <code>null</code> * if no menu bar has been set. * @return the current menu bar, or <code>null</code> if none has been set * * @deprecated As of Swing version 1.0.3, * replaced by <code>getJMenuBar()</code>. */ @Deprecated public JMenuBar getMenuBar() { return getRootPane().getMenuBar(); } /** * Returns the current <code>JMenuBar</code> for this * <code>JInternalFrame</code>, or <code>null</code> * if no menu bar has been set. * * @return the <code>JMenuBar</code> used by this internal frame * @see #setJMenuBar */ public JMenuBar getJMenuBar() { return getRootPane().getJMenuBar(); } /** * Sets the <code>menuBar</code> property for this <code>JInternalFrame</code>. * * @param m the <code>JMenuBar</code> to use in this internal frame * @see #getJMenuBar * @deprecated As of Swing version 1.0.3 * replaced by <code>setJMenuBar(JMenuBar m)</code>. */ @Deprecated public void setMenuBar(JMenuBar m) { JMenuBar oldValue = getMenuBar(); getRootPane().setJMenuBar(m); firePropertyChange(MENU_BAR_PROPERTY, oldValue, m); } /** * Sets the <code>menuBar</code> property for this <code>JInternalFrame</code>. * * @param m the <code>JMenuBar</code> to use in this internal frame * @see #getJMenuBar */ @BeanProperty(preferred = true, description = "The menu bar for accessing pulldown menus from this internal frame.") public void setJMenuBar(JMenuBar m){ JMenuBar oldValue = getMenuBar(); getRootPane().setJMenuBar(m); firePropertyChange(MENU_BAR_PROPERTY, oldValue, m); } // implements javax.swing.RootPaneContainer /** * Returns the content pane for this internal frame. * @return the content pane */ public Container getContentPane() { return getRootPane().getContentPane(); } /** * Sets this <code>JInternalFrame</code>'s <code>contentPane</code> * property. * * @param c the content pane for this internal frame * * @exception java.awt.IllegalComponentStateException (a runtime * exception) if the content pane parameter is <code>null</code> * @see RootPaneContainer#getContentPane */ @BeanProperty(hidden = true, description = "The client area of the internal frame where child components are normally inserted.") public void setContentPane(Container c) { Container oldValue = getContentPane(); getRootPane().setContentPane(c); firePropertyChange(CONTENT_PANE_PROPERTY, oldValue, c); } /** * Returns the layered pane for this internal frame. * * @return a <code>JLayeredPane</code> object * @see RootPaneContainer#setLayeredPane * @see RootPaneContainer#getLayeredPane */ public JLayeredPane getLayeredPane() { return getRootPane().getLayeredPane(); } /** * Sets this <code>JInternalFrame</code>'s * <code>layeredPane</code> property. * * @param layered the <code>JLayeredPane</code> for this internal frame * * @exception java.awt.IllegalComponentStateException (a runtime * exception) if the layered pane parameter is <code>null</code> * @see RootPaneContainer#setLayeredPane */ @BeanProperty(hidden = true, description = "The pane which holds the various desktop layers.") public void setLayeredPane(JLayeredPane layered) { JLayeredPane oldValue = getLayeredPane(); getRootPane().setLayeredPane(layered); firePropertyChange(LAYERED_PANE_PROPERTY, oldValue, layered); } /** * Returns the glass pane for this internal frame. * * @return the glass pane * @see RootPaneContainer#setGlassPane */ public Component getGlassPane() { return getRootPane().getGlassPane(); } /** * Sets this <code>JInternalFrame</code>'s * <code>glassPane</code> property. * * @param glass the glass pane for this internal frame * @see RootPaneContainer#getGlassPane */ @BeanProperty(hidden = true, description = "A transparent pane used for menu rendering.") public void setGlassPane(Component glass) { Component oldValue = getGlassPane(); getRootPane().setGlassPane(glass); firePropertyChange(GLASS_PANE_PROPERTY, oldValue, glass); } /** * Returns the <code>rootPane</code> object for this internal frame. * * @return the <code>rootPane</code> property * @see RootPaneContainer#getRootPane */ @BeanProperty(hidden = true, description = "The root pane used by this internal frame.") public JRootPane getRootPane() { return rootPane; } /** * Sets the <code>rootPane</code> property * for this <code>JInternalFrame</code>. * This method is called by the constructor. * * @param root the new <code>JRootPane</code> object */ protected void setRootPane(JRootPane root) { if(rootPane != null) { remove(rootPane); } JRootPane oldValue = getRootPane(); rootPane = root; if(rootPane != null) { boolean checkingEnabled = isRootPaneCheckingEnabled(); try { setRootPaneCheckingEnabled(false); add(rootPane, BorderLayout.CENTER); } finally { setRootPaneCheckingEnabled(checkingEnabled); } } firePropertyChange(ROOT_PANE_PROPERTY, oldValue, root); } /** * Sets whether this <code>JInternalFrame</code> can be closed by * some user action. * @param b a boolean value, where <code>true</code> means this internal frame can be closed */ @BeanProperty(preferred = true, description = "Indicates whether this internal frame can be closed.") public void setClosable(boolean b) { Boolean oldValue = closable ? Boolean.TRUE : Boolean.FALSE; Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE; closable = b; firePropertyChange("closable", oldValue, newValue); } /** * Returns whether this <code>JInternalFrame</code> can be closed by * some user action. * @return <code>true</code> if this internal frame can be closed */ public boolean isClosable() { return closable; } /** * Returns whether this <code>JInternalFrame</code> is currently closed. * @return <code>true</code> if this internal frame is closed, <code>false</code> otherwise */ public boolean isClosed() { return isClosed; } /** * Closes this internal frame if the argument is <code>true</code>. * Do not invoke this method with a <code>false</code> argument; * the result of invoking <code>setClosed(false)</code> * is unspecified. * * <p> * * If the internal frame is already closed, * this method does nothing and returns immediately. * Otherwise, * this method begins by firing * an <code>INTERNAL_FRAME_CLOSING</code> event. * Then this method sets the <code>closed</code> property to <code>true</code> * unless a listener vetoes the property change. * This method finishes by making the internal frame * invisible and unselected, * and then firing an <code>INTERNAL_FRAME_CLOSED</code> event. * * <p> * * <b>Note:</b> * To reuse an internal frame that has been closed, * you must add it to a container * (even if you never removed it from its previous container). * Typically, this container will be the <code>JDesktopPane</code> * that previously contained the internal frame. * * @param b must be <code>true</code> * * @exception PropertyVetoException when the attempt to set the * property is vetoed by the <code>JInternalFrame</code> * * @see #isClosed() * @see #setDefaultCloseOperation * @see #dispose * @see javax.swing.event.InternalFrameEvent#INTERNAL_FRAME_CLOSING */ @BeanProperty(description = "Indicates whether this internal frame has been closed.") public void setClosed(boolean b) throws PropertyVetoException { if (isClosed == b) { return; } Boolean oldValue = isClosed ? Boolean.TRUE : Boolean.FALSE; Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE; if (b) { fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING); } fireVetoableChange(IS_CLOSED_PROPERTY, oldValue, newValue); isClosed = b; if (isClosed) { setVisible(false); } firePropertyChange(IS_CLOSED_PROPERTY, oldValue, newValue); if (isClosed) { dispose(); } else if (!opened) { /* this bogus -- we haven't defined what setClosed(false) means. */ // fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED); // opened = true; } } /** * Sets whether the <code>JInternalFrame</code> can be resized by some * user action. * * @param b a boolean, where <code>true</code> means this internal frame can be resized */ @BeanProperty(preferred = true, description = "Determines whether this internal frame can be resized by the user.") public void setResizable(boolean b) { Boolean oldValue = resizable ? Boolean.TRUE : Boolean.FALSE; Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE; resizable = b; firePropertyChange("resizable", oldValue, newValue); } /** * Returns whether the <code>JInternalFrame</code> can be resized * by some user action. * * @return <code>true</code> if this internal frame can be resized, <code>false</code> otherwise */ public boolean isResizable() { // don't allow resizing when maximized. return isMaximum ? false : resizable; } /** * Sets the <code>iconable</code> property, * which must be <code>true</code> * for the user to be able to * make the <code>JInternalFrame</code> an icon. * Some look and feels might not implement iconification; * they will ignore this property. * * @param b a boolean, where <code>true</code> means this internal frame can be iconified */ @BeanProperty(preferred = true, description = "Determines whether this internal frame can be iconified.") public void setIconifiable(boolean b) { Boolean oldValue = iconable ? Boolean.TRUE : Boolean.FALSE; Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE; iconable = b; firePropertyChange("iconable", oldValue, newValue); } /** * Gets the <code>iconable</code> property, * which by default is <code>false</code>. * * @return the value of the <code>iconable</code> property. * * @see #setIconifiable */ public boolean isIconifiable() { return iconable; } /** * Returns whether the <code>JInternalFrame</code> is currently iconified. * * @return <code>true</code> if this internal frame is iconified */ public boolean isIcon() { return isIcon; } /** * Iconifies or de-iconifies this internal frame, * if the look and feel supports iconification. * If the internal frame's state changes to iconified, * this method fires an <code>INTERNAL_FRAME_ICONIFIED</code> event. * If the state changes to de-iconified, * an <code>INTERNAL_FRAME_DEICONIFIED</code> event is fired. * * @param b a boolean, where <code>true</code> means to iconify this internal frame and * <code>false</code> means to de-iconify it * @exception PropertyVetoException when the attempt to set the * property is vetoed by the <code>JInternalFrame</code> * * @see InternalFrameEvent#INTERNAL_FRAME_ICONIFIED * @see InternalFrameEvent#INTERNAL_FRAME_DEICONIFIED */ @BeanProperty(description = "The image displayed when this internal frame is minimized.") public void setIcon(boolean b) throws PropertyVetoException { if (isIcon == b) { return; } /* If an internal frame is being iconified before it has a parent, (e.g., client wants it to start iconic), create the parent if possible so that we can place the icon in its proper place on the desktop. I am not sure the call to validate() is necessary, since we are not going to display this frame yet */ firePropertyChange("ancestor", null, getParent()); Boolean oldValue = isIcon ? Boolean.TRUE : Boolean.FALSE; Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE; fireVetoableChange(IS_ICON_PROPERTY, oldValue, newValue); isIcon = b; firePropertyChange(IS_ICON_PROPERTY, oldValue, newValue); if (b) fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_ICONIFIED); else fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_DEICONIFIED); } /** * Sets the <code>maximizable</code> property, * which determines whether the <code>JInternalFrame</code> * can be maximized by * some user action. * Some look and feels might not support maximizing internal frames; * they will ignore this property. * * @param b <code>true</code> to specify that this internal frame should be maximizable; <code>false</code> to specify that it should not be */ @BeanProperty(preferred = true, description = "Determines whether this internal frame can be maximized.") public void setMaximizable(boolean b) { Boolean oldValue = maximizable ? Boolean.TRUE : Boolean.FALSE; Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE; maximizable = b; firePropertyChange("maximizable", oldValue, newValue); } /** * Gets the value of the <code>maximizable</code> property. * * @return the value of the <code>maximizable</code> property * @see #setMaximizable */ public boolean isMaximizable() { return maximizable; } /** * Returns whether the <code>JInternalFrame</code> is currently maximized. * * @return <code>true</code> if this internal frame is maximized, <code>false</code> otherwise */ public boolean isMaximum() { return isMaximum; } /** * Maximizes and restores this internal frame. A maximized frame is resized to * fully fit the <code>JDesktopPane</code> area associated with the * <code>JInternalFrame</code>. * A restored frame's size is set to the <code>JInternalFrame</code>'s * actual size. * * @param b a boolean, where <code>true</code> maximizes this internal frame and <code>false</code> * restores it * @exception PropertyVetoException when the attempt to set the * property is vetoed by the <code>JInternalFrame</code> */ @BeanProperty(description = "Indicates whether this internal frame is maximized.") public void setMaximum(boolean b) throws PropertyVetoException { if (isMaximum == b) { return; } Boolean oldValue = isMaximum ? Boolean.TRUE : Boolean.FALSE; Boolean newValue = b ? Boolean.TRUE : Boolean.FALSE; fireVetoableChange(IS_MAXIMUM_PROPERTY, oldValue, newValue); /* setting isMaximum above the event firing means that property listeners that, for some reason, test it will get it wrong... See, for example, getNormalBounds() */ isMaximum = b; firePropertyChange(IS_MAXIMUM_PROPERTY, oldValue, newValue); } /** * Returns the title of the <code>JInternalFrame</code>. * * @return a <code>String</code> containing this internal frame's title * @see #setTitle */ public String getTitle() { return title; } /** * Sets the <code>JInternalFrame</code> title. <code>title</code> * may have a <code>null</code> value. * @see #getTitle * * @param title the <code>String</code> to display in the title bar */ @BeanProperty(preferred = true, description = "The text displayed in the title bar.") public void setTitle(String title) { String oldValue = this.title; this.title = title; firePropertyChange(TITLE_PROPERTY, oldValue, title); } /** * Selects or deselects the internal frame * if it's showing. * A <code>JInternalFrame</code> normally draws its title bar * differently if it is * the selected frame, which indicates to the user that this * internal frame has the focus. * When this method changes the state of the internal frame * from deselected to selected, it fires an * <code>InternalFrameEvent.INTERNAL_FRAME_ACTIVATED</code> event. * If the change is from selected to deselected, * an <code>InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED</code> event * is fired. * * @param selected a boolean, where <code>true</code> means this internal frame * should become selected (currently active) * and <code>false</code> means it should become deselected * @exception PropertyVetoException when the attempt to set the * property is vetoed by the <code>JInternalFrame</code> * * @see #isShowing * @see InternalFrameEvent#INTERNAL_FRAME_ACTIVATED * @see InternalFrameEvent#INTERNAL_FRAME_DEACTIVATED */ @BeanProperty(description = "Indicates whether this internal frame is currently the active frame.") public void setSelected(boolean selected) throws PropertyVetoException { // The InternalFrame may already be selected, but the focus // may be outside it, so restore the focus to the subcomponent // which previously had it. See Bug 4302764. if (selected && isSelected) { restoreSubcomponentFocus(); return; } // The internal frame or the desktop icon must be showing to allow // selection. We may deselect even if neither is showing. if ((isSelected == selected) || (selected && (isIcon ? !desktopIcon.isShowing() : !isShowing()))) { return; } Boolean oldValue = isSelected ? Boolean.TRUE : Boolean.FALSE; Boolean newValue = selected ? Boolean.TRUE : Boolean.FALSE; fireVetoableChange(IS_SELECTED_PROPERTY, oldValue, newValue); /* We don't want to leave focus in the previously selected frame, so we have to set it to *something* in case it doesn't get set in some other way (as if a user clicked on a component that doesn't request focus). If this call is happening because the user clicked on a component that will want focus, then it will get transfered there later. We test for parent.isShowing() above, because AWT throws a NPE if you try to request focus on a lightweight before its parent has been made visible */ if (selected) { restoreSubcomponentFocus(); } isSelected = selected; firePropertyChange(IS_SELECTED_PROPERTY, oldValue, newValue); if (isSelected) fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_ACTIVATED); else fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED); repaint(); } /** * Returns whether the <code>JInternalFrame</code> is the * currently "selected" or active frame. * * @return <code>true</code> if this internal frame is currently selected (active) * @see #setSelected */ public boolean isSelected() { return isSelected; } /** * Sets an image to be displayed in the titlebar of this internal frame (usually * in the top-left corner). * Some look and feels might not support displaying an icon in the titlebar. * * This image is not the <code>desktopIcon</code> object, which * is the image displayed in the <code>JDesktop</code> when * this internal frame is iconified. * * Passing <code>null</code> to this function is valid, * but the look and feel can choose the appropriate behavior * for that situation, such as displaying no icon * or a default icon for the look and feel. * * @param icon the <code>Icon</code> to display in the title bar * @see #getFrameIcon */ @BeanProperty(description = "The icon shown in the top-left corner of this internal frame.") public void setFrameIcon(Icon icon) { Icon oldIcon = frameIcon; frameIcon = icon; firePropertyChange(FRAME_ICON_PROPERTY, oldIcon, icon); } /** * Returns the image displayed in the title bar of this internal frame (usually * in the top-left corner). * * @return the <code>Icon</code> displayed in the title bar * @see #setFrameIcon */ public Icon getFrameIcon() { return frameIcon; } /** * Convenience method that moves this component to position 0 if its * parent is a <code>JLayeredPane</code>. */ public void moveToFront() { if (isIcon()) { if (getDesktopIcon().getParent() instanceof JLayeredPane) { ((JLayeredPane)getDesktopIcon().getParent()). moveToFront(getDesktopIcon()); } } else if (getParent() instanceof JLayeredPane) { ((JLayeredPane)getParent()).moveToFront(this); } } /** * Convenience method that moves this component to position -1 if its * parent is a <code>JLayeredPane</code>. */ public void moveToBack() { if (isIcon()) { if (getDesktopIcon().getParent() instanceof JLayeredPane) { ((JLayeredPane)getDesktopIcon().getParent()). moveToBack(getDesktopIcon()); } } else if (getParent() instanceof JLayeredPane) { ((JLayeredPane)getParent()).moveToBack(this); } } /** * Returns the last <code>Cursor</code> that was set by the * <code>setCursor</code> method that is not a resizable * <code>Cursor</code>. * * @return the last non-resizable <code>Cursor</code> * @since 1.6 */ @BeanProperty(bound = false) public Cursor getLastCursor() { return lastCursor; } /** * {@inheritDoc} * @since 1.6 */ public void setCursor(Cursor cursor) { if (cursor == null) { lastCursor = null; super.setCursor(cursor); return; } int type = cursor.getType(); if (!(type == Cursor.SW_RESIZE_CURSOR || type == Cursor.SE_RESIZE_CURSOR || type == Cursor.NW_RESIZE_CURSOR || type == Cursor.NE_RESIZE_CURSOR || type == Cursor.N_RESIZE_CURSOR || type == Cursor.S_RESIZE_CURSOR || type == Cursor.W_RESIZE_CURSOR || type == Cursor.E_RESIZE_CURSOR)) { lastCursor = cursor; } super.setCursor(cursor); } /** * Convenience method for setting the layer attribute of this component. * * @param layer an <code>Integer</code> object specifying this * frame's desktop layer * @throws NullPointerException if {@code layer} is {@code null} * @see JLayeredPane */ @BeanProperty(bound = false, expert = true, description = "Specifies what desktop layer is used.") public void setLayer(Integer layer) { if(getParent() != null && getParent() instanceof JLayeredPane) { // Normally we want to do this, as it causes the LayeredPane // to draw properly. JLayeredPane p = (JLayeredPane)getParent(); p.setLayer(this, layer.intValue(), p.getPosition(this)); } else { // Try to do the right thing JLayeredPane.putLayer(this, layer.intValue()); if(getParent() != null) getParent().repaint(getX(), getY(), getWidth(), getHeight()); } } /** * Convenience method for setting the layer attribute of this component. * The method <code>setLayer(Integer)</code> should be used for * layer values predefined in <code>JLayeredPane</code>. * When using <code>setLayer(int)</code>, care must be taken not to * accidentally clash with those values. * * @param layer an integer specifying this internal frame's desktop layer * * @since 1.3 * * @see #setLayer(Integer) * @see JLayeredPane */ @BeanProperty(bound = false, expert = true, description = "Specifies what desktop layer is used.") public void setLayer(int layer) { this.setLayer(Integer.valueOf(layer)); } /** * Convenience method for getting the layer attribute of this component. * * @return an <code>Integer</code> object specifying this * frame's desktop layer * @see JLayeredPane */ public int getLayer() { return JLayeredPane.getLayer(this); } /** * Convenience method that searches the ancestor hierarchy for a * <code>JDesktop</code> instance. If <code>JInternalFrame</code> * finds none, the <code>desktopIcon</code> tree is searched. * * @return the <code>JDesktopPane</code> this internal frame belongs to, * or <code>null</code> if none is found */ @BeanProperty(bound = false) public JDesktopPane getDesktopPane() { Container p; // Search upward for desktop p = getParent(); while(p != null && !(p instanceof JDesktopPane)) p = p.getParent(); if(p == null) { // search its icon parent for desktop p = getDesktopIcon().getParent(); while(p != null && !(p instanceof JDesktopPane)) p = p.getParent(); } return (JDesktopPane)p; } /** * Sets the <code>JDesktopIcon</code> associated with this * <code>JInternalFrame</code>. * * @param d the <code>JDesktopIcon</code> to display on the desktop * @see #getDesktopIcon */ @BeanProperty(description = "The icon shown when this internal frame is minimized.") public void setDesktopIcon(JDesktopIcon d) { JDesktopIcon oldValue = getDesktopIcon(); desktopIcon = d; firePropertyChange("desktopIcon", oldValue, d); } /** * Returns the <code>JDesktopIcon</code> used when this * <code>JInternalFrame</code> is iconified. * * @return the <code>JDesktopIcon</code> displayed on the desktop * @see #setDesktopIcon */ public JDesktopIcon getDesktopIcon() { return desktopIcon; } /** * If the <code>JInternalFrame</code> is not in maximized state, returns * <code>getBounds()</code>; otherwise, returns the bounds that the * <code>JInternalFrame</code> would be restored to. * * @return a <code>Rectangle</code> containing the bounds of this * frame when in the normal state * @since 1.3 */ public Rectangle getNormalBounds() { /* we used to test (!isMaximum) here, but since this method is used by the property listener for the IS_MAXIMUM_PROPERTY, it ended up getting the wrong answer... Since normalBounds get set to null when the frame is restored, this should work better */ if (normalBounds != null) { return normalBounds; } else { return getBounds(); } } /** * Sets the normal bounds for this internal frame, the bounds that * this internal frame would be restored to from its maximized state. * This method is intended for use only by desktop managers. * * @param r the bounds that this internal frame should be restored to * @since 1.3 */ public void setNormalBounds(Rectangle r) { normalBounds = r; } /** * If this <code>JInternalFrame</code> is active, * returns the child that has focus. * Otherwise, returns <code>null</code>. * * @return the component with focus, or <code>null</code> if no children have focus * @since 1.3 */ public Component getFocusOwner() { if (isSelected()) { return lastFocusOwner; } return null; } /** * Returns the child component of this <code>JInternalFrame</code> * that will receive the * focus when this <code>JInternalFrame</code> is selected. * If this <code>JInternalFrame</code> is * currently selected, this method returns the same component as * the <code>getFocusOwner</code> method. * If this <code>JInternalFrame</code> is not selected, * then the child component that most recently requested focus will be * returned. If no child component has ever requested focus, then this * <code>JInternalFrame</code>'s initial focusable component is returned. * If no such * child exists, then this <code>JInternalFrame</code>'s default component * to focus is returned. * * @return the child component that will receive focus when this * <code>JInternalFrame</code> is selected * @see #getFocusOwner * @see #isSelected * @since 1.4 */ @BeanProperty(bound = false) public Component getMostRecentFocusOwner() { if (isSelected()) { return getFocusOwner(); } if (lastFocusOwner != null) { return lastFocusOwner; } FocusTraversalPolicy policy = getFocusTraversalPolicy(); if (policy instanceof InternalFrameFocusTraversalPolicy) { return ((InternalFrameFocusTraversalPolicy)policy). getInitialComponent(this); } Component toFocus = policy.getDefaultComponent(this); if (toFocus != null) { return toFocus; } return getContentPane(); } /** * Requests the internal frame to restore focus to the * last subcomponent that had focus. This is used by the UI when * the user selected this internal frame -- * for example, by clicking on the title bar. * * @since 1.3 */ public void restoreSubcomponentFocus() { if (isIcon()) { SwingUtilities2.compositeRequestFocus(getDesktopIcon()); } else { Component component = KeyboardFocusManager.getCurrentKeyboardFocusManager().getPermanentFocusOwner(); if ((component == null) || !SwingUtilities.isDescendingFrom(component, this)) { // FocusPropertyChangeListener will eventually update // lastFocusOwner. As focus requests are asynchronous // lastFocusOwner may be accessed before it has been correctly // updated. To avoid any problems, lastFocusOwner is immediately // set, assuming the request will succeed. setLastFocusOwner(getMostRecentFocusOwner()); if (lastFocusOwner == null) { // Make sure focus is restored somewhere, so that // we don't leave a focused component in another frame while // this frame is selected. setLastFocusOwner(getContentPane()); } lastFocusOwner.requestFocus(); } } } private void setLastFocusOwner(Component component) { lastFocusOwner = component; } /** * Moves and resizes this component. Unlike other components, * this implementation also forces re-layout, so that frame * decorations such as the title bar are always redisplayed. * * @param x an integer giving the component's new horizontal position * measured in pixels from the left of its container * @param y an integer giving the component's new vertical position, * measured in pixels from the bottom of its container * @param width an integer giving the component's new width in pixels * @param height an integer giving the component's new height in pixels */ @SuppressWarnings("deprecation") public void reshape(int x, int y, int width, int height) { super.reshape(x, y, width, height); validate(); repaint(); } /////////////////////////// // Frame/Window equivalents /////////////////////////// /** * Adds the specified listener to receive internal * frame events from this internal frame. * * @param l the internal frame listener */ public void addInternalFrameListener(InternalFrameListener l) { // remind: sync ?? listenerList.add(InternalFrameListener.class, l); // remind: needed? enableEvents(0); // turn on the newEventsOnly flag in Component. } /** * Removes the specified internal frame listener so that it no longer * receives internal frame events from this internal frame. * * @param l the internal frame listener */ public void removeInternalFrameListener(InternalFrameListener l) { // remind: sync?? listenerList.remove(InternalFrameListener.class, l); } /** * Returns an array of all the <code>InternalFrameListener</code>s added * to this <code>JInternalFrame</code> with * <code>addInternalFrameListener</code>. * * @return all of the <code>InternalFrameListener</code>s added or an empty * array if no listeners have been added * @since 1.4 * * @see #addInternalFrameListener */ @BeanProperty(bound = false) public InternalFrameListener[] getInternalFrameListeners() { return listenerList.getListeners(InternalFrameListener.class); } // remind: name ok? all one method ok? need to be synchronized? /** * Fires an internal frame event. * * @param id the type of the event being fired; one of the following: * <ul> * <li><code>InternalFrameEvent.INTERNAL_FRAME_OPENED</code> * <li><code>InternalFrameEvent.INTERNAL_FRAME_CLOSING</code> * <li><code>InternalFrameEvent.INTERNAL_FRAME_CLOSED</code> * <li><code>InternalFrameEvent.INTERNAL_FRAME_ICONIFIED</code> * <li><code>InternalFrameEvent.INTERNAL_FRAME_DEICONIFIED</code> * <li><code>InternalFrameEvent.INTERNAL_FRAME_ACTIVATED</code> * <li><code>InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED</code> * </ul> * If the event type is not one of the above, nothing happens. */ protected void fireInternalFrameEvent(int id){ Object[] listeners = listenerList.getListenerList(); InternalFrameEvent e = null; for (int i = listeners.length -2; i >=0; i -= 2){ if (listeners[i] == InternalFrameListener.class){ if (e == null){ e = new InternalFrameEvent(this, id); // System.out.println("InternalFrameEvent: " + e.paramString()); } switch(e.getID()) { case InternalFrameEvent.INTERNAL_FRAME_OPENED: ((InternalFrameListener)listeners[i+1]).internalFrameOpened(e); break; case InternalFrameEvent.INTERNAL_FRAME_CLOSING: ((InternalFrameListener)listeners[i+1]).internalFrameClosing(e); break; case InternalFrameEvent.INTERNAL_FRAME_CLOSED: ((InternalFrameListener)listeners[i+1]).internalFrameClosed(e); break; case InternalFrameEvent.INTERNAL_FRAME_ICONIFIED: ((InternalFrameListener)listeners[i+1]).internalFrameIconified(e); break; case InternalFrameEvent.INTERNAL_FRAME_DEICONIFIED: ((InternalFrameListener)listeners[i+1]).internalFrameDeiconified(e); break; case InternalFrameEvent.INTERNAL_FRAME_ACTIVATED: ((InternalFrameListener)listeners[i+1]).internalFrameActivated(e); break; case InternalFrameEvent.INTERNAL_FRAME_DEACTIVATED: ((InternalFrameListener)listeners[i+1]).internalFrameDeactivated(e); break; default: break; } } } /* we could do it off the event, but at the moment, that's not how I'm implementing it */ // if (id == InternalFrameEvent.INTERNAL_FRAME_CLOSING) { // doDefaultCloseAction(); // } } /** * Fires an * <code>INTERNAL_FRAME_CLOSING</code> event * and then performs the action specified by * the internal frame's default close operation. * This method is typically invoked by the * look-and-feel-implemented action handler * for the internal frame's close button. * * @since 1.3 * @see #setDefaultCloseOperation * @see javax.swing.event.InternalFrameEvent#INTERNAL_FRAME_CLOSING */ public void doDefaultCloseAction() { fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSING); switch(defaultCloseOperation) { case DO_NOTHING_ON_CLOSE: break; case HIDE_ON_CLOSE: setVisible(false); if (isSelected()) try { setSelected(false); } catch (PropertyVetoException pve) {} /* should this activate the next frame? that's really desktopmanager's policy... */ break; case DISPOSE_ON_CLOSE: try { fireVetoableChange(IS_CLOSED_PROPERTY, Boolean.FALSE, Boolean.TRUE); isClosed = true; setVisible(false); firePropertyChange(IS_CLOSED_PROPERTY, Boolean.FALSE, Boolean.TRUE); dispose(); } catch (PropertyVetoException pve) {} break; default: break; } } /** * Sets the operation that will happen by default when * the user initiates a "close" on this internal frame. * The possible choices are: * <br><br> * <dl> * <dt><code>DO_NOTHING_ON_CLOSE</code> * <dd> Do nothing. * This requires the program to handle the operation * in the <code>internalFrameClosing</code> method * of a registered <code>InternalFrameListener</code> object. * <dt><code>HIDE_ON_CLOSE</code> * <dd> Automatically make the internal frame invisible. * <dt><code>DISPOSE_ON_CLOSE</code> * <dd> Automatically dispose of the internal frame. * </dl> * <p> * The default value is <code>DISPOSE_ON_CLOSE</code>. * Before performing the specified close operation, * the internal frame fires * an <code>INTERNAL_FRAME_CLOSING</code> event. * * @param operation one of the following constants defined in * <code>javax.swing.WindowConstants</code> * (an interface implemented by * <code>JInternalFrame</code>): * <code>DO_NOTHING_ON_CLOSE</code>, * <code>HIDE_ON_CLOSE</code>, or * <code>DISPOSE_ON_CLOSE</code> * * @see #addInternalFrameListener * @see #getDefaultCloseOperation * @see #setVisible * @see #dispose * @see InternalFrameEvent#INTERNAL_FRAME_CLOSING */ public void setDefaultCloseOperation(int operation) { this.defaultCloseOperation = operation; } /** * Returns the default operation that occurs when the user * initiates a "close" on this internal frame. * @return the operation that will occur when the user closes the internal * frame * @see #setDefaultCloseOperation */ public int getDefaultCloseOperation() { return defaultCloseOperation; } /** * Causes subcomponents of this <code>JInternalFrame</code> * to be laid out at their preferred size. Internal frames that are * iconized or maximized are first restored and then packed. If the * internal frame is unable to be restored its state is not changed * and will not be packed. * * @see java.awt.Window#pack */ public void pack() { try { if (isIcon()) { setIcon(false); } else if (isMaximum()) { setMaximum(false); } } catch(PropertyVetoException e) { return; } setSize(getPreferredSize()); validate(); } /** * If the internal frame is not visible, * brings the internal frame to the front, * makes it visible, * and attempts to select it. * The first time the internal frame is made visible, * this method also fires an <code>INTERNAL_FRAME_OPENED</code> event. * This method does nothing if the internal frame is already visible. * Invoking this method * has the same result as invoking * <code>setVisible(true)</code>. * * @see #moveToFront * @see #setSelected * @see InternalFrameEvent#INTERNAL_FRAME_OPENED * @see #setVisible */ @SuppressWarnings("deprecation") public void show() { // bug 4312922 if (isVisible()) { //match the behavior of setVisible(true): do nothing return; } // bug 4149505 if (!opened) { fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_OPENED); opened = true; } /* icon default visibility is false; set it to true so that it shows up when user iconifies frame */ getDesktopIcon().setVisible(true); toFront(); super.show(); if (isIcon) { return; } if (!isSelected()) { try { setSelected(true); } catch (PropertyVetoException pve) {} } } @SuppressWarnings("deprecation") public void hide() { if (isIcon()) { getDesktopIcon().setVisible(false); } super.hide(); } /** * Makes this internal frame * invisible, unselected, and closed. * If the frame is not already closed, * this method fires an * <code>INTERNAL_FRAME_CLOSED</code> event. * The results of invoking this method are similar to * <code>setClosed(true)</code>, * but <code>dispose</code> always succeeds in closing * the internal frame and does not fire * an <code>INTERNAL_FRAME_CLOSING</code> event. * * @see javax.swing.event.InternalFrameEvent#INTERNAL_FRAME_CLOSED * @see #setVisible * @see #setSelected * @see #setClosed */ public void dispose() { if (isVisible()) { setVisible(false); } if (!isClosed) { firePropertyChange(IS_CLOSED_PROPERTY, Boolean.FALSE, Boolean.TRUE); isClosed = true; } fireInternalFrameEvent(InternalFrameEvent.INTERNAL_FRAME_CLOSED); } /** * Brings this internal frame to the front. * Places this internal frame at the top of the stacking order * and makes the corresponding adjustment to other visible internal * frames. * * @see java.awt.Window#toFront * @see #moveToFront */ public void toFront() { moveToFront(); } /** * Sends this internal frame to the back. * Places this internal frame at the bottom of the stacking order * and makes the corresponding adjustment to other visible * internal frames. * * @see java.awt.Window#toBack * @see #moveToBack */ public void toBack() { moveToBack(); } /** * Does nothing because <code>JInternalFrame</code>s must always be roots of a focus * traversal cycle. * * @param focusCycleRoot this value is ignored * @see #isFocusCycleRoot * @see java.awt.Container#setFocusTraversalPolicy * @see java.awt.Container#getFocusTraversalPolicy * @since 1.4 */ public final void setFocusCycleRoot(boolean focusCycleRoot) { } /** * Always returns <code>true</code> because all <code>JInternalFrame</code>s must be * roots of a focus traversal cycle. * * @return <code>true</code> * @see #setFocusCycleRoot * @see java.awt.Container#setFocusTraversalPolicy * @see java.awt.Container#getFocusTraversalPolicy * @since 1.4 */ public final boolean isFocusCycleRoot() { return true; } /** * Always returns <code>null</code> because <code>JInternalFrame</code>s * must always be roots of a focus * traversal cycle. * * @return <code>null</code> * @see java.awt.Container#isFocusCycleRoot() * @since 1.4 */ @BeanProperty(bound = false) public final Container getFocusCycleRootAncestor() { return null; } /** * Gets the warning string that is displayed with this internal frame. * Since an internal frame is always secure (since it's fully * contained within a window that might need a warning string) * this method always returns <code>null</code>. * @return <code>null</code> * @see java.awt.Window#getWarningString */ @BeanProperty(bound = false) public final String getWarningString() { return null; } /** * See <code>readObject</code> and <code>writeObject</code> * in <code>JComponent</code> for more * information about serialization in Swing. */ private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); if (getUIClassID().equals(uiClassID)) { byte count = JComponent.getWriteObjCounter(this); JComponent.setWriteObjCounter(this, --count); if (count == 0 && ui != null) { boolean old = isRootPaneCheckingEnabled(); try { setRootPaneCheckingEnabled(false); ui.installUI(this); } finally { setRootPaneCheckingEnabled(old); } } } } /* Called from the JComponent's EnableSerializationFocusListener to * do any Swing-specific pre-serialization configuration. */ void compWriteObjectNotify() { // need to disable rootpane checking for InternalFrame: 4172083 boolean old = isRootPaneCheckingEnabled(); try { setRootPaneCheckingEnabled(false); super.compWriteObjectNotify(); } finally { setRootPaneCheckingEnabled(old); } } /** * Returns a string representation of this <code>JInternalFrame</code>. * This method * is intended to be used only for debugging purposes, and the * content and format of the returned string may vary between * implementations. The returned string may be empty but may not * be <code>null</code>. * * @return a string representation of this <code>JInternalFrame</code> */ protected String paramString() { String rootPaneString = (rootPane != null ? rootPane.toString() : ""); String rootPaneCheckingEnabledString = (rootPaneCheckingEnabled ? "true" : "false"); String closableString = (closable ? "true" : "false"); String isClosedString = (isClosed ? "true" : "false"); String maximizableString = (maximizable ? "true" : "false"); String isMaximumString = (isMaximum ? "true" : "false"); String iconableString = (iconable ? "true" : "false"); String isIconString = (isIcon ? "true" : "false"); String resizableString = (resizable ? "true" : "false"); String isSelectedString = (isSelected ? "true" : "false"); String frameIconString = (frameIcon != null ? frameIcon.toString() : ""); String titleString = (title != null ? title : ""); String desktopIconString = (desktopIcon != null ? desktopIcon.toString() : ""); String openedString = (opened ? "true" : "false"); String defaultCloseOperationString; if (defaultCloseOperation == HIDE_ON_CLOSE) { defaultCloseOperationString = "HIDE_ON_CLOSE"; } else if (defaultCloseOperation == DISPOSE_ON_CLOSE) { defaultCloseOperationString = "DISPOSE_ON_CLOSE"; } else if (defaultCloseOperation == DO_NOTHING_ON_CLOSE) { defaultCloseOperationString = "DO_NOTHING_ON_CLOSE"; } else defaultCloseOperationString = ""; return super.paramString() + ",closable=" + closableString + ",defaultCloseOperation=" + defaultCloseOperationString + ",desktopIcon=" + desktopIconString + ",frameIcon=" + frameIconString + ",iconable=" + iconableString + ",isClosed=" + isClosedString + ",isIcon=" + isIconString + ",isMaximum=" + isMaximumString + ",isSelected=" + isSelectedString + ",maximizable=" + maximizableString + ",opened=" + openedString + ",resizable=" + resizableString + ",rootPane=" + rootPaneString + ",rootPaneCheckingEnabled=" + rootPaneCheckingEnabledString + ",title=" + titleString; } // ======= begin optimized frame dragging defence code ============== boolean isDragging = false; boolean danger = false; /** * Overridden to allow optimized painting when the * internal frame is being dragged. */ protected void paintComponent(Graphics g) { if (isDragging) { // System.out.println("ouch"); danger = true; } super.paintComponent(g); } // ======= end optimized frame dragging defence code ============== ///////////////// // Accessibility support //////////////// /** * Gets the <code>AccessibleContext</code> associated with this * <code>JInternalFrame</code>. * For internal frames, the <code>AccessibleContext</code> * takes the form of an * <code>AccessibleJInternalFrame</code> object. * A new <code>AccessibleJInternalFrame</code> instance is created if necessary. * * @return an <code>AccessibleJInternalFrame</code> that serves as the * <code>AccessibleContext</code> of this * <code>JInternalFrame</code> * @see AccessibleJInternalFrame */ @BeanProperty(bound = false) public AccessibleContext getAccessibleContext() { if (accessibleContext == null) { accessibleContext = new AccessibleJInternalFrame(); } return accessibleContext; } /** * This class implements accessibility support for the * <code>JInternalFrame</code> class. It provides an implementation of the * Java Accessibility API appropriate to internal frame user-interface * elements. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans™ * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. */ @SuppressWarnings("serial") // Same-version serialization only protected class AccessibleJInternalFrame extends AccessibleJComponent implements AccessibleValue { /** * Get the accessible name of this object. * * @return the localized name of the object -- can be <code>null</code> if this * object does not have a name * @see #setAccessibleName */ public String getAccessibleName() { String name = accessibleName; if (name == null) { name = (String)getClientProperty(AccessibleContext.ACCESSIBLE_NAME_PROPERTY); } if (name == null) { name = getTitle(); } return name; } /** * Get the role of this object. * * @return an instance of AccessibleRole describing the role of the * object * @see AccessibleRole */ public AccessibleRole getAccessibleRole() { return AccessibleRole.INTERNAL_FRAME; } /** * Gets the AccessibleValue associated with this object. In the * implementation of the Java Accessibility API for this class, * returns this object, which is responsible for implementing the * <code>AccessibleValue</code> interface on behalf of itself. * * @return this object */ public AccessibleValue getAccessibleValue() { return this; } // // AccessibleValue methods // /** * Get the value of this object as a Number. * * @return value of the object -- can be <code>null</code> if this object does not * have a value */ public Number getCurrentAccessibleValue() { return Integer.valueOf(getLayer()); } /** * Set the value of this object as a Number. * * @return <code>true</code> if the value was set */ public boolean setCurrentAccessibleValue(Number n) { // TIGER - 4422535 if (n == null) { return false; } setLayer(Integer.valueOf(n.intValue())); return true; } /** * Get the minimum value of this object as a Number. * * @return Minimum value of the object; <code>null</code> if this object does not * have a minimum value */ public Number getMinimumAccessibleValue() { return Integer.MIN_VALUE; } /** * Get the maximum value of this object as a Number. * * @return Maximum value of the object; <code>null</code> if this object does not * have a maximum value */ public Number getMaximumAccessibleValue() { return Integer.MAX_VALUE; } } // AccessibleJInternalFrame /** * This component represents an iconified version of a * <code>JInternalFrame</code>. * This API should NOT BE USED by Swing applications, as it will go * away in future versions of Swing as its functionality is moved into * <code>JInternalFrame</code>. This class is public only so that * UI objects can display a desktop icon. If an application * wants to display a desktop icon, it should create a * <code>JInternalFrame</code> instance and iconify it. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans™ * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @author David Kloba */ @SuppressWarnings("serial") // Same-version serialization only public static class JDesktopIcon extends JComponent implements Accessible { JInternalFrame internalFrame; /** * Creates an icon for an internal frame. * * @param f the <code>JInternalFrame</code> * for which the icon is created */ public JDesktopIcon(JInternalFrame f) { setVisible(false); setInternalFrame(f); updateUI(); } /** * Returns the look-and-feel object that renders this component. * * @return the <code>DesktopIconUI</code> object that renders * this component */ public DesktopIconUI getUI() { return (DesktopIconUI)ui; } /** * Sets the look-and-feel object that renders this component. * * @param ui the <code>DesktopIconUI</code> look-and-feel object * @see UIDefaults#getUI */ public void setUI(DesktopIconUI ui) { super.setUI(ui); } /** * Returns the <code>JInternalFrame</code> that this * <code>DesktopIcon</code> is associated with. * * @return the <code>JInternalFrame</code> with which this icon * is associated */ public JInternalFrame getInternalFrame() { return internalFrame; } /** * Sets the <code>JInternalFrame</code> with which this * <code>DesktopIcon</code> is associated. * * @param f the <code>JInternalFrame</code> with which this icon * is associated */ public void setInternalFrame(JInternalFrame f) { internalFrame = f; } /** * Convenience method to ask the icon for the <code>Desktop</code> * object it belongs to. * * @return the <code>JDesktopPane</code> that contains this * icon's internal frame, or <code>null</code> if none found */ public JDesktopPane getDesktopPane() { if(getInternalFrame() != null) return getInternalFrame().getDesktopPane(); return null; } /** * Notification from the <code>UIManager</code> that the look and feel * has changed. * Replaces the current UI object with the latest version from the * <code>UIManager</code>. * * @see JComponent#updateUI */ public void updateUI() { boolean hadUI = (ui != null); setUI((DesktopIconUI)UIManager.getUI(this)); invalidate(); Dimension r = getPreferredSize(); setSize(r.width, r.height); if (internalFrame != null && internalFrame.getUI() != null) { // don't do this if UI not created yet SwingUtilities.updateComponentTreeUI(internalFrame); } } /* This method is called if updateUI was called on the associated * JInternalFrame. It's necessary to avoid infinite recursion. */ void updateUIWhenHidden() { /* Update this UI and any associated internal frame */ setUI((DesktopIconUI)UIManager.getUI(this)); Dimension r = getPreferredSize(); setSize(r.width, r.height); invalidate(); Component[] children = getComponents(); if (children != null) { for (Component child : children) { SwingUtilities.updateComponentTreeUI(child); } } } /** * Returns the name of the look-and-feel * class that renders this component. * * @return the string "DesktopIconUI" * @see JComponent#getUIClassID * @see UIDefaults#getUI */ public String getUIClassID() { return "DesktopIconUI"; } //////////////// // Serialization support //////////////// private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); if (getUIClassID().equals("DesktopIconUI")) { byte count = JComponent.getWriteObjCounter(this); JComponent.setWriteObjCounter(this, --count); if (count == 0 && ui != null) { ui.installUI(this); } } } ///////////////// // Accessibility support //////////////// /** * Gets the AccessibleContext associated with this JDesktopIcon. * For desktop icons, the AccessibleContext takes the form of an * AccessibleJDesktopIcon. * A new AccessibleJDesktopIcon instance is created if necessary. * * @return an AccessibleJDesktopIcon that serves as the * AccessibleContext of this JDesktopIcon */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) { accessibleContext = new AccessibleJDesktopIcon(); } return accessibleContext; } /** * This class implements accessibility support for the * <code>JInternalFrame.JDesktopIcon</code> class. It provides an * implementation of the Java Accessibility API appropriate to * desktop icon user-interface elements. * <p> * <strong>Warning:</strong> * Serialized objects of this class will not be compatible with * future Swing releases. The current serialization support is * appropriate for short term storage or RMI between applications running * the same version of Swing. As of 1.4, support for long term storage * of all JavaBeans™ * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. */ @SuppressWarnings("serial") // Same-version serialization only protected class AccessibleJDesktopIcon extends AccessibleJComponent implements AccessibleValue { /** * Gets the role of this object. * * @return an instance of AccessibleRole describing the role of the * object * @see AccessibleRole */ public AccessibleRole getAccessibleRole() { return AccessibleRole.DESKTOP_ICON; } /** * Gets the AccessibleValue associated with this object. In the * implementation of the Java Accessibility API for this class, * returns this object, which is responsible for implementing the * <code>AccessibleValue</code> interface on behalf of itself. * * @return this object */ public AccessibleValue getAccessibleValue() { return this; } // // AccessibleValue methods // /** * Gets the value of this object as a <code>Number</code>. * * @return value of the object -- can be <code>null</code> if this object does not * have a value */ public Number getCurrentAccessibleValue() { AccessibleContext a = JDesktopIcon.this.getInternalFrame().getAccessibleContext(); AccessibleValue v = a.getAccessibleValue(); if (v != null) { return v.getCurrentAccessibleValue(); } else { return null; } } /** * Sets the value of this object as a <code>Number</code>. * * @return <code>true</code> if the value was set */ public boolean setCurrentAccessibleValue(Number n) { // TIGER - 4422535 if (n == null) { return false; } AccessibleContext a = JDesktopIcon.this.getInternalFrame().getAccessibleContext(); AccessibleValue v = a.getAccessibleValue(); if (v != null) { return v.setCurrentAccessibleValue(n); } else { return false; } } /** * Gets the minimum value of this object as a <code>Number</code>. * * @return minimum value of the object; <code>null</code> if this object does not * have a minimum value */ public Number getMinimumAccessibleValue() { AccessibleContext a = JDesktopIcon.this.getInternalFrame().getAccessibleContext(); if (a instanceof AccessibleValue) { return ((AccessibleValue)a).getMinimumAccessibleValue(); } else { return null; } } /** * Gets the maximum value of this object as a <code>Number</code>. * * @return maximum value of the object; <code>null</code> if this object does not * have a maximum value */ public Number getMaximumAccessibleValue() { AccessibleContext a = JDesktopIcon.this.getInternalFrame().getAccessibleContext(); if (a instanceof AccessibleValue) { return ((AccessibleValue)a).getMaximumAccessibleValue(); } else { return null; } } } // AccessibleJDesktopIcon } }