Home » openjdk-7 » javax » swing » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2010, 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.util.List;
   29   import java.util.ArrayList;
   30   import java.util.Vector;
   31   import javax.swing.plaf;
   32   import javax.accessibility;
   33   
   34   import java.awt.Component;
   35   import java.awt.Container;
   36   import java.awt.DefaultFocusTraversalPolicy;
   37   import java.awt.FocusTraversalPolicy;
   38   import java.awt.Window;
   39   import java.io.ObjectOutputStream;
   40   import java.io.ObjectInputStream;
   41   import java.io.IOException;
   42   import java.beans.PropertyVetoException;
   43   import java.util.Set;
   44   import java.util.TreeSet;
   45   
   46   /**
   47    * A container used to create a multiple-document interface or a virtual desktop.
   48    * You create <code>JInternalFrame</code> objects and add them to the
   49    * <code>JDesktopPane</code>. <code>JDesktopPane</code> extends
   50    * <code>JLayeredPane</code> to manage the potentially overlapping internal
   51    * frames. It also maintains a reference to an instance of
   52    * <code>DesktopManager</code> that is set by the UI
   53    * class for the current look and feel (L&F).  Note that <code>JDesktopPane</code>
   54    * does not support borders.
   55    * <p>
   56    * This class is normally used as the parent of <code>JInternalFrames</code>
   57    * to provide a pluggable <code>DesktopManager</code> object to the
   58    * <code>JInternalFrames</code>. The <code>installUI</code> of the
   59    * L&F specific implementation is responsible for setting the
   60    * <code>desktopManager</code> variable appropriately.
   61    * When the parent of a <code>JInternalFrame</code> is a <code>JDesktopPane</code>,
   62    * it should delegate most of its behavior to the <code>desktopManager</code>
   63    * (closing, resizing, etc).
   64    * <p>
   65    * For further documentation and examples see
   66    * <a href="http://java.sun.com/docs/books/tutorial/uiswing/components/internalframe.html">How to Use Internal Frames</a>,
   67    * a section in <em>The Java Tutorial</em>.
   68    * <p>
   69    * <strong>Warning:</strong> Swing is not thread safe. For more
   70    * information see <a
   71    * href="package-summary.html#threading">Swing's Threading
   72    * Policy</a>.
   73    * <p>
   74    * <strong>Warning:</strong>
   75    * Serialized objects of this class will not be compatible with
   76    * future Swing releases. The current serialization support is
   77    * appropriate for short term storage or RMI between applications running
   78    * the same version of Swing.  As of 1.4, support for long term storage
   79    * of all JavaBeans<sup><font size="-2">TM</font></sup>
   80    * has been added to the <code>java.beans</code> package.
   81    * Please see {@link java.beans.XMLEncoder}.
   82    *
   83    * @see JInternalFrame
   84    * @see JInternalFrame.JDesktopIcon
   85    * @see DesktopManager
   86    *
   87    * @author David Kloba
   88    */
   89   public class JDesktopPane extends JLayeredPane implements Accessible
   90   {
   91       /**
   92        * @see #getUIClassID
   93        * @see #readObject
   94        */
   95       private static final String uiClassID = "DesktopPaneUI";
   96   
   97       transient DesktopManager desktopManager;
   98   
   99       private transient JInternalFrame selectedFrame = null;
  100   
  101       /**
  102         * Indicates that the entire contents of the item being dragged
  103         * should appear inside the desktop pane.
  104         *
  105         * @see #OUTLINE_DRAG_MODE
  106         * @see #setDragMode
  107         */
  108       public static final int LIVE_DRAG_MODE = 0;
  109   
  110       /**
  111         * Indicates that an outline only of the item being dragged
  112         * should appear inside the desktop pane.
  113         *
  114         * @see #LIVE_DRAG_MODE
  115         * @see #setDragMode
  116         */
  117       public static final int OUTLINE_DRAG_MODE = 1;
  118   
  119       private int dragMode = LIVE_DRAG_MODE;
  120       private boolean dragModeSet = false;
  121       private transient List<JInternalFrame> framesCache;
  122       private boolean componentOrderCheckingEnabled = true;
  123       private boolean componentOrderChanged = false;
  124   
  125       /**
  126        * Creates a new <code>JDesktopPane</code>.
  127        */
  128       public JDesktopPane() {
  129           setUIProperty("opaque", Boolean.TRUE);
  130           setFocusCycleRoot(true);
  131   
  132           setFocusTraversalPolicy(new LayoutFocusTraversalPolicy() {
  133               public Component getDefaultComponent(Container c) {
  134                   JInternalFrame jifArray[] = getAllFrames();
  135                   Component comp = null;
  136                   for (JInternalFrame jif : jifArray) {
  137                       comp = jif.getFocusTraversalPolicy().getDefaultComponent(jif);
  138                       if (comp != null) {
  139                           break;
  140                       }
  141                   }
  142                   return comp;
  143               }
  144           });
  145           updateUI();
  146       }
  147   
  148       /**
  149        * Returns the L&F object that renders this component.
  150        *
  151        * @return the <code>DesktopPaneUI</code> object that
  152        *   renders this component
  153        */
  154       public DesktopPaneUI getUI() {
  155           return (DesktopPaneUI)ui;
  156       }
  157   
  158       /**
  159        * Sets the L&F object that renders this component.
  160        *
  161        * @param ui  the DesktopPaneUI L&F object
  162        * @see UIDefaults#getUI
  163        * @beaninfo
  164        *        bound: true
  165        *       hidden: true
  166        *    attribute: visualUpdate true
  167        *  description: The UI object that implements the Component's LookAndFeel.
  168        */
  169       public void setUI(DesktopPaneUI ui) {
  170           super.setUI(ui);
  171       }
  172   
  173       /**
  174        * Sets the "dragging style" used by the desktop pane.
  175        * You may want to change to one mode or another for
  176        * performance or aesthetic reasons.
  177        *
  178        * @param dragMode the style of drag to use for items in the Desktop
  179        *
  180        * @see #LIVE_DRAG_MODE
  181        * @see #OUTLINE_DRAG_MODE
  182        *
  183        * @beaninfo
  184        *        bound: true
  185        *  description: Dragging style for internal frame children.
  186        *         enum: LIVE_DRAG_MODE JDesktopPane.LIVE_DRAG_MODE
  187        *               OUTLINE_DRAG_MODE JDesktopPane.OUTLINE_DRAG_MODE
  188        * @since 1.3
  189        */
  190       public void setDragMode(int dragMode) {
  191           int oldDragMode = this.dragMode;
  192           this.dragMode = dragMode;
  193           firePropertyChange("dragMode", oldDragMode, this.dragMode);
  194           dragModeSet = true;
  195        }
  196   
  197       /**
  198        * Gets the current "dragging style" used by the desktop pane.
  199        * @return either <code>Live_DRAG_MODE</code> or
  200        *   <code>OUTLINE_DRAG_MODE</code>
  201        * @see #setDragMode
  202        * @since 1.3
  203        */
  204        public int getDragMode() {
  205            return dragMode;
  206        }
  207   
  208       /**
  209        * Returns the <code>DesktopManger</code> that handles
  210        * desktop-specific UI actions.
  211        */
  212       public DesktopManager getDesktopManager() {
  213           return desktopManager;
  214       }
  215   
  216       /**
  217        * Sets the <code>DesktopManger</code> that will handle
  218        * desktop-specific UI actions. This may be overridden by
  219        * {@code LookAndFeel}.
  220        *
  221        * @param d the <code>DesktopManager</code> to use
  222        *
  223        * @beaninfo
  224        *        bound: true
  225        *  description: Desktop manager to handle the internal frames in the
  226        *               desktop pane.
  227        */
  228       public void setDesktopManager(DesktopManager d) {
  229           DesktopManager oldValue = desktopManager;
  230           desktopManager = d;
  231           firePropertyChange("desktopManager", oldValue, desktopManager);
  232       }
  233   
  234       /**
  235        * Notification from the <code>UIManager</code> that the L&F has changed.
  236        * Replaces the current UI object with the latest version from the
  237        * <code>UIManager</code>.
  238        *
  239        * @see JComponent#updateUI
  240        */
  241       public void updateUI() {
  242           setUI((DesktopPaneUI)UIManager.getUI(this));
  243       }
  244   
  245   
  246       /**
  247        * Returns the name of the L&F class that renders this component.
  248        *
  249        * @return the string "DesktopPaneUI"
  250        * @see JComponent#getUIClassID
  251        * @see UIDefaults#getUI
  252        */
  253       public String getUIClassID() {
  254           return uiClassID;
  255       }
  256   
  257       /**
  258        * Returns all <code>JInternalFrames</code> currently displayed in the
  259        * desktop. Returns iconified frames as well as expanded frames.
  260        *
  261        * @return an array of <code>JInternalFrame</code> objects
  262        */
  263       public JInternalFrame[] getAllFrames() {
  264           int i, count;
  265           JInternalFrame[] results;
  266           Vector<JInternalFrame> vResults = new Vector<JInternalFrame>(10);
  267   
  268           count = getComponentCount();
  269           for(i = 0; i < count; i++) {
  270               Component next = getComponent(i);
  271               if(next instanceof JInternalFrame)
  272                   vResults.addElement((JInternalFrame) next);
  273               else if(next instanceof JInternalFrame.JDesktopIcon)  {
  274                   JInternalFrame tmp = ((JInternalFrame.JDesktopIcon)next).getInternalFrame();
  275                   if(tmp != null)
  276                       vResults.addElement(tmp);
  277               }
  278           }
  279   
  280           results = new JInternalFrame[vResults.size()];
  281           vResults.copyInto(results);
  282   
  283           return results;
  284       }
  285   
  286       /** Returns the currently active <code>JInternalFrame</code>
  287         * in this <code>JDesktopPane</code>, or <code>null</code>
  288         * if no <code>JInternalFrame</code> is currently active.
  289         *
  290         * @return the currently active <code>JInternalFrame</code> or
  291         *   <code>null</code>
  292         * @since 1.3
  293         */
  294   
  295       public JInternalFrame getSelectedFrame() {
  296         return selectedFrame;
  297       }
  298   
  299       /** Sets the currently active <code>JInternalFrame</code>
  300        *  in this <code>JDesktopPane</code>. This method is used to bridge
  301        *  the package gap between JDesktopPane and the platform implementation
  302        *  code and should not be called directly. To visually select the frame
  303        *  the client must call JInternalFrame.setSelected(true) to activate
  304        *  the frame.
  305        *  @see JInternalFrame#setSelected(boolean)
  306        *
  307        * @param f the internal frame that's currently selected
  308        * @since 1.3
  309        */
  310   
  311       public void setSelectedFrame(JInternalFrame f) {
  312         selectedFrame = f;
  313       }
  314   
  315       /**
  316        * Returns all <code>JInternalFrames</code> currently displayed in the
  317        * specified layer of the desktop. Returns iconified frames as well
  318        * expanded frames.
  319        *
  320        * @param layer  an int specifying the desktop layer
  321        * @return an array of <code>JInternalFrame</code> objects
  322        * @see JLayeredPane
  323        */
  324       public JInternalFrame[] getAllFramesInLayer(int layer) {
  325           int i, count;
  326           JInternalFrame[] results;
  327           Vector<JInternalFrame> vResults = new Vector<JInternalFrame>(10);
  328   
  329           count = getComponentCount();
  330           for(i = 0; i < count; i++) {
  331               Component next = getComponent(i);
  332               if(next instanceof JInternalFrame) {
  333                   if(((JInternalFrame)next).getLayer() == layer)
  334                       vResults.addElement((JInternalFrame) next);
  335               } else if(next instanceof JInternalFrame.JDesktopIcon)  {
  336                   JInternalFrame tmp = ((JInternalFrame.JDesktopIcon)next).getInternalFrame();
  337                   if(tmp != null && tmp.getLayer() == layer)
  338                       vResults.addElement(tmp);
  339               }
  340           }
  341   
  342           results = new JInternalFrame[vResults.size()];
  343           vResults.copyInto(results);
  344   
  345           return results;
  346       }
  347   
  348       private List<JInternalFrame> getFrames() {
  349           Component c;
  350           Set<ComponentPosition> set = new TreeSet<ComponentPosition>();
  351           for (int i = 0; i < getComponentCount(); i++) {
  352               c = getComponent(i);
  353               if (c instanceof JInternalFrame) {
  354                   set.add(new ComponentPosition((JInternalFrame)c, getLayer(c),
  355                       i));
  356               }
  357               else if (c instanceof JInternalFrame.JDesktopIcon)  {
  358                   c = ((JInternalFrame.JDesktopIcon)c).getInternalFrame();
  359                   set.add(new ComponentPosition((JInternalFrame)c, getLayer(c),
  360                       i));
  361               }
  362           }
  363           List<JInternalFrame> frames = new ArrayList<JInternalFrame>(
  364                   set.size());
  365           for (ComponentPosition position : set) {
  366               frames.add(position.component);
  367           }
  368           return frames;
  369      }
  370   
  371       private static class ComponentPosition implements
  372           Comparable<ComponentPosition> {
  373           private final JInternalFrame component;
  374           private final int layer;
  375           private final int zOrder;
  376   
  377           ComponentPosition(JInternalFrame component, int layer, int zOrder) {
  378               this.component = component;
  379               this.layer = layer;
  380               this.zOrder = zOrder;
  381           }
  382   
  383           public int compareTo(ComponentPosition o) {
  384               int delta = o.layer - layer;
  385               if (delta == 0) {
  386                   return zOrder - o.zOrder;
  387               }
  388               return delta;
  389           }
  390       }
  391   
  392       private JInternalFrame getNextFrame(JInternalFrame f, boolean forward) {
  393           verifyFramesCache();
  394           if (f == null) {
  395               return getTopInternalFrame();
  396           }
  397           int i = framesCache.indexOf(f);
  398           if (i == -1 || framesCache.size() == 1) {
  399               /* error */
  400               return null;
  401           }
  402           if (forward) {
  403               // navigate to the next frame
  404               if (++i == framesCache.size()) {
  405                   /* wrap */
  406                   i = 0;
  407               }
  408           }
  409           else {
  410               // navigate to the previous frame
  411               if (--i == -1) {
  412                   /* wrap */
  413                   i = framesCache.size() - 1;
  414               }
  415           }
  416           return framesCache.get(i);
  417       }
  418   
  419       JInternalFrame getNextFrame(JInternalFrame f) {
  420           return getNextFrame(f, true);
  421       }
  422   
  423       private JInternalFrame getTopInternalFrame() {
  424           if (framesCache.size() == 0) {
  425               return null;
  426           }
  427           return framesCache.get(0);
  428       }
  429   
  430       private void updateFramesCache() {
  431           framesCache = getFrames();
  432       }
  433   
  434       private void verifyFramesCache() {
  435           // If framesCache is dirty, then recreate it.
  436           if (componentOrderChanged) {
  437               componentOrderChanged = false;
  438               updateFramesCache();
  439           }
  440       }
  441   
  442       /**
  443        * Selects the next <code>JInternalFrame</code> in this desktop pane.
  444        *
  445        * @param forward a boolean indicating which direction to select in;
  446        *        <code>true</code> for forward, <code>false</code> for
  447        *        backward
  448        * @return the JInternalFrame that was selected or <code>null</code>
  449        *         if nothing was selected
  450        * @since 1.6
  451        */
  452       public JInternalFrame selectFrame(boolean forward) {
  453           JInternalFrame selectedFrame = getSelectedFrame();
  454           JInternalFrame frameToSelect = getNextFrame(selectedFrame, forward);
  455           if (frameToSelect == null) {
  456               return null;
  457           }
  458           // Maintain navigation traversal order until an
  459           // external stack change, such as a click on a frame.
  460           setComponentOrderCheckingEnabled(false);
  461           if (forward && selectedFrame != null) {
  462               selectedFrame.moveToBack();  // For Windows MDI fidelity.
  463           }
  464           try { frameToSelect.setSelected(true);
  465           } catch (PropertyVetoException pve) {}
  466           setComponentOrderCheckingEnabled(true);
  467           return frameToSelect;
  468       }
  469   
  470       /*
  471        * Sets whether component order checking is enabled.
  472        * @param enable a boolean value, where <code>true</code> means
  473        * a change in component order will cause a change in the keyboard
  474        * navigation order.
  475        * @since 1.6
  476        */
  477       void setComponentOrderCheckingEnabled(boolean enable) {
  478           componentOrderCheckingEnabled = enable;
  479       }
  480   
  481       /**
  482        * {@inheritDoc}
  483        * @since 1.6
  484        */
  485       protected void addImpl(Component comp, Object constraints, int index) {
  486           super.addImpl(comp, constraints, index);
  487           if (componentOrderCheckingEnabled) {
  488               if (comp instanceof JInternalFrame ||
  489                   comp instanceof JInternalFrame.JDesktopIcon) {
  490                   componentOrderChanged = true;
  491               }
  492           }
  493       }
  494   
  495       /**
  496        * {@inheritDoc}
  497        * @since 1.6
  498        */
  499       public void remove(int index) {
  500           if (componentOrderCheckingEnabled) {
  501               Component comp = getComponent(index);
  502               if (comp instanceof JInternalFrame ||
  503                   comp instanceof JInternalFrame.JDesktopIcon) {
  504                   componentOrderChanged = true;
  505               }
  506           }
  507           super.remove(index);
  508       }
  509   
  510       /**
  511        * {@inheritDoc}
  512        * @since 1.6
  513        */
  514       public void removeAll() {
  515           if (componentOrderCheckingEnabled) {
  516               int count = getComponentCount();
  517               for (int i = 0; i < count; i++) {
  518                   Component comp = getComponent(i);
  519                   if (comp instanceof JInternalFrame ||
  520                       comp instanceof JInternalFrame.JDesktopIcon) {
  521                       componentOrderChanged = true;
  522                       break;
  523                   }
  524               }
  525           }
  526           super.removeAll();
  527       }
  528   
  529       /**
  530        * {@inheritDoc}
  531        * @since 1.6
  532        */
  533       public void setComponentZOrder(Component comp, int index) {
  534           super.setComponentZOrder(comp, index);
  535           if (componentOrderCheckingEnabled) {
  536               if (comp instanceof JInternalFrame ||
  537                   comp instanceof JInternalFrame.JDesktopIcon) {
  538                   componentOrderChanged = true;
  539               }
  540           }
  541       }
  542   
  543       /**
  544        * See readObject() and writeObject() in JComponent for more
  545        * information about serialization in Swing.
  546        */
  547       private void writeObject(ObjectOutputStream s) throws IOException {
  548           s.defaultWriteObject();
  549           if (getUIClassID().equals(uiClassID)) {
  550               byte count = JComponent.getWriteObjCounter(this);
  551               JComponent.setWriteObjCounter(this, --count);
  552               if (count == 0 && ui != null) {
  553                   ui.installUI(this);
  554               }
  555           }
  556       }
  557   
  558       void setUIProperty(String propertyName, Object value) {
  559           if (propertyName == "dragMode") {
  560               if (!dragModeSet) {
  561                   setDragMode(((Integer)value).intValue());
  562                   dragModeSet = false;
  563               }
  564           } else {
  565               super.setUIProperty(propertyName, value);
  566           }
  567       }
  568   
  569       /**
  570        * Returns a string representation of this <code>JDesktopPane</code>.
  571        * This method is intended to be used only for debugging purposes, and the
  572        * content and format of the returned string may vary between
  573        * implementations. The returned string may be empty but may not
  574        * be <code>null</code>.
  575        *
  576        * @return  a string representation of this <code>JDesktopPane</code>
  577        */
  578       protected String paramString() {
  579           String desktopManagerString = (desktopManager != null ?
  580                                          desktopManager.toString() : "");
  581   
  582           return super.paramString() +
  583           ",desktopManager=" + desktopManagerString;
  584       }
  585   
  586   /////////////////
  587   // Accessibility support
  588   ////////////////
  589   
  590       /**
  591        * Gets the <code>AccessibleContext</code> associated with this
  592        * <code>JDesktopPane</code>. For desktop panes, the
  593        * <code>AccessibleContext</code> takes the form of an
  594        * <code>AccessibleJDesktopPane</code>.
  595        * A new <code>AccessibleJDesktopPane</code> instance is created if necessary.
  596        *
  597        * @return an <code>AccessibleJDesktopPane</code> that serves as the
  598        *         <code>AccessibleContext</code> of this <code>JDesktopPane</code>
  599        */
  600       public AccessibleContext getAccessibleContext() {
  601           if (accessibleContext == null) {
  602               accessibleContext = new AccessibleJDesktopPane();
  603           }
  604           return accessibleContext;
  605       }
  606   
  607       /**
  608        * This class implements accessibility support for the
  609        * <code>JDesktopPane</code> class.  It provides an implementation of the
  610        * Java Accessibility API appropriate to desktop pane user-interface
  611        * elements.
  612        * <p>
  613        * <strong>Warning:</strong>
  614        * Serialized objects of this class will not be compatible with
  615        * future Swing releases. The current serialization support is
  616        * appropriate for short term storage or RMI between applications running
  617        * the same version of Swing.  As of 1.4, support for long term storage
  618        * of all JavaBeans<sup><font size="-2">TM</font></sup>
  619        * has been added to the <code>java.beans</code> package.
  620        * Please see {@link java.beans.XMLEncoder}.
  621        */
  622       protected class AccessibleJDesktopPane extends AccessibleJComponent {
  623   
  624           /**
  625            * Get the role of this object.
  626            *
  627            * @return an instance of AccessibleRole describing the role of the
  628            * object
  629            * @see AccessibleRole
  630            */
  631           public AccessibleRole getAccessibleRole() {
  632               return AccessibleRole.DESKTOP_PANE;
  633           }
  634       }
  635   }

Home » openjdk-7 » javax » swing » [javadoc | source]