home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / awt / swing / JRootPane.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  19.1 KB  |  493 lines

  1. /*
  2.  * @(#)JRootPane.java    1.20 98/02/02
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package java.awt.swing;
  21.  
  22. import java.awt.*;
  23. import java.awt.event.*;
  24. import java.awt.accessibility.*;
  25. import java.util.Vector;
  26. import java.io.Serializable;
  27.  
  28.  
  29. /** The JRootPane component is made up of several components.
  30.   * In order they are:
  31.   * <PRE>
  32.   *      JRootPane
  33.   *          glassPane
  34.   *          layeredPane 
  35.   *              [menuBar]
  36.   *              contentPane
  37.   * </PRE>
  38.   * The menuBar component is optional and may or may
  39.   * exist at any time. The layeredPane, contentPane, and glassPane will always
  40.   * be available. 
  41.   * <p>
  42.   * The <code>contentPane</code> should be the parent of any children of 
  43.   * the JRootPane. You would normally do something like this:
  44.   * <PRE>
  45.   *       rootPane.add(child);
  46.   * </PRE>
  47.   * Using JRootPane the proper semantic is:
  48.   * <PRE>
  49.   *       rootPane.getContentPane().add(child);
  50.   * </PRE>
  51.   * The same priniciple holds true for setting layout managers, removing 
  52.   * components, listing children, etc. All these methods should normally 
  53.   * be sent to the <code>contentPane</code> instead of to the JRootPane.
  54.   * The <code>contentPane</code> is always non-null. Attempting to set it 
  55.   * to null generates an exception. The default <code>contentPane</code> 
  56.   * has a BorderLayout manager set on it. 
  57.   * <p>
  58.   * If a JMenuBar component is set on the JRootPane, it is positioned 
  59.   * along the upper edge of the frame. The <code>contentPane</code> is
  60.   * adjusted in location and size to fill the remaining area. 
  61.   * <p>
  62.   * The JMenuBar and the <code>contentPane</code> are added 
  63.   * to the <code>layeredPane</code> component at the 
  64.   * JLayeredPane.FRAME_CONTENT_LAYER layer. 
  65.   * <p>
  66.   * The <code>layeredPane</code> is an instance of the JLayeredPane class.
  67.   * It's purpose is to be the parent of all children of the JRootPane. It 
  68.   * provides the ability to add components at several layers. This is very
  69.   * useful when working with menu popups, dialog boxes, or during dragging.
  70.   * Situations where you need to place a component over the top of all 
  71.   * other normal components. The <code>layeredPane</code> is always non-null. 
  72.   * Attempting to set it to null generates an exception. 
  73.   * <p>
  74.   * The <code>glassPane</code> is always added as the first child of the 
  75.   * JRootPane. This allows the glass component to get in the way of all 
  76.   * mouse events, as well as providing a convient place to draw above all
  77.   * other components. The <code>glassPane</code> is always non-null.
  78.   * Attempting to set it to null generates an exception. Developers should
  79.   * use <code>setVisible</code> on the glassPane to control when the 
  80.   * <code>glassPane</code> displays over the other children. By default the 
  81.   * <code>glassPane</code> is not visible. 
  82.   * <p>
  83.   * The JRootPane uses a custom LayoutManager. This LayoutManager insures 
  84.   * the following:
  85.   * <OL>
  86.   * <LI>The <code>glassPane</code>, if present, fills the entire viewable
  87.   *     area of the JRootPane (bounds - insets).
  88.   * <LI>The <code>layeredPane</code> fills the entire viewable area of the
  89.   *     JRootPane. (bounds - insets)
  90.   * <LI>The <code>menuBar</code> is positioned at the upper edge of the 
  91.   *     layeredPane().
  92.   * <LI>The <code>contentPane</code> fills the entire viewable area, 
  93.   *     minus the MenuBar, if present.
  94.   * </OL>
  95.   * Any other views in the JRootPane view hierarchy are ignored.
  96.   * If you replace the LayoutManager of the JRootPane, you are responsible for managing
  97.   * all of these views.
  98.   * <p>
  99.   * Warning: serialized objects of this class will not be compatible with
  100.   * future swing releases.  The current serialization support is appropriate
  101.   * for short term storage or RMI between Swing1.0 applications.  It will
  102.   * not be possible to load serialized Swing1.0 objects with future releases
  103.   * of Swing.  The JDK1.2 release of Swing will be the compatibility
  104.   * baseline for the serialized form of Swing objects.
  105.   *
  106.   * @see JLayeredPane
  107.   * @see JMenuBar
  108.   * @see JWindow
  109.   * @see JFrame
  110.   * @see JDialog
  111.   *
  112.   * @version 1.20 02/02/98
  113.   * @author David Kloba
  114.   */
  115. /// PENDING(klobad) Who should be opaque in this component?
  116. public class JRootPane extends JComponent implements Accessible {
  117.     protected JMenuBar menuBar;
  118.     protected Container contentPane;
  119.     protected JLayeredPane layeredPane;
  120.     protected Component glassPane;
  121.     protected JButton defaultButton; 
  122.     protected DefaultAction defaultPressAction;   
  123.     protected DefaultAction defaultReleaseAction;
  124.  
  125.     public JRootPane() {
  126.         setGlassPane(createGlassPane());
  127.         setLayeredPane(createLayeredPane());
  128.         setContentPane(createContentPane());
  129.         setLayout(createRootLayout());
  130.         setDoubleBuffered(true);
  131.         setBackground(UIManager.getColor("control"));
  132.     }
  133.  
  134.     /** Called by the constructor methods to create the default layeredPane. 
  135.       * Bt default it creates a new JLayeredPane. 
  136.       */
  137.     protected JLayeredPane createLayeredPane() {
  138.         JLayeredPane p = new JLayeredPane();
  139.         p.setName(this.getName()+".layeredPane");
  140.         return p;
  141.     }
  142.  
  143.     /** Called by the constructor methods to create the default contentPane. 
  144.      * By default this method creates a new JComponent add sets a 
  145.      * BorderLayout as its LayoutManager.
  146.      */
  147.     protected Container createContentPane() {
  148.         JComponent c = new JPanel();
  149.         c.setName(this.getName()+".contentPane");
  150.         c.setLayout(new BorderLayout() {
  151.             /* This BorderLayout subclass maps a null constraint to CENTER.
  152.              * Although the reference BorderLayout also does this, some VMs
  153.              * throw an IllegalArgumentException.
  154.              */
  155.             public void addLayoutComponent(Component comp, Object constraints) {
  156.                 if (constraints == null) {
  157.                     constraints = BorderLayout.CENTER;
  158.                 }
  159.                 super.addLayoutComponent(comp, constraints);
  160.             }
  161.         });
  162.         return c;
  163.     }
  164.  
  165.     /** Called by the constructor methods to create the default glassPane. 
  166.       * By default this method creates a new JComponent with visibility 
  167.       * set to false.
  168.       */
  169.     protected Component createGlassPane() {
  170.         JComponent c = new JPanel();
  171.         c.setName(this.getName()+".glassPane");
  172.         c.setVisible(false);
  173.         ((JPanel)c).setOpaque(false);
  174.         return c;
  175.     }
  176.  
  177.     /** Called by the constructor methods to create the default layoutManager. */
  178.     protected LayoutManager createRootLayout() {
  179.         return new RootLayout();
  180.     } 
  181.  
  182.     public void setMenuBar(JMenuBar menu) {
  183.         if(menuBar != null && menuBar.getParent() == layeredPane)
  184.             layeredPane.remove(menuBar);
  185.         menuBar = menu;
  186.  
  187.         if(menuBar != null)
  188.             layeredPane.add(menuBar, JLayeredPane.FRAME_CONTENT_LAYER);
  189.     }
  190.     public JMenuBar getMenuBar() { return menuBar; }
  191.  
  192.     public void setContentPane(Container content) {
  193.         if(content == null)
  194.             throw new IllegalComponentStateException("contentPane cannot be set to null.");
  195.         if(contentPane != null && contentPane.getParent() == layeredPane)
  196.             layeredPane.remove(contentPane);
  197.         contentPane = content;
  198.  
  199.         layeredPane.add(contentPane, JLayeredPane.FRAME_CONTENT_LAYER);
  200.     }
  201.     public Container getContentPane() { return contentPane; }
  202.  
  203. // PENDING(klobad) Should this reparent the contentPane and MenuBar?
  204.     public void setLayeredPane(JLayeredPane layered) {
  205.         if(layered == null)
  206.             throw new IllegalComponentStateException("layeredPane cannot be set to null.");
  207.         if(layeredPane != null && layeredPane.getParent() == this)
  208.             this.remove(layeredPane);
  209.         layeredPane = layered;
  210.  
  211.         this.add(layeredPane, -1);
  212.     }
  213.     public JLayeredPane getLayeredPane() { return layeredPane; }
  214.  
  215.     /**
  216.      * Sets a specified Component to be the glass pane for this
  217.      * root pane.  The glass pane should normally be a lightweight,
  218.      * transparent component, because it will be made visible when
  219.      * ever the root pane needs to grab input events.  For example,
  220.      * only one JInternalFrame is ever active when using a
  221.      * DefaultDesktop, and any inactive JInternalFrames' glass panes
  222.      * are made visible so that clicking anywhere within an inactive
  223.      * JInternalFrame can activate it.
  224.      * @param glass the Component to use as the glass pane for this
  225.      *              JRootPane.
  226.      */
  227.     public void setGlassPane(Component glass) {
  228.         if (glass == null) {
  229.             throw new NullPointerException("glassPane cannot be set to null.");
  230.         }
  231.  
  232.         boolean visible = false;
  233.         if (glassPane != null && glassPane.getParent() == this) {
  234.             this.remove(glassPane);
  235.             visible = glassPane.isVisible();
  236.         }
  237.  
  238.         glass.setVisible(visible);
  239.         glassPane = glass;
  240.         this.add(glassPane, 0);
  241.         if (visible) {
  242.             repaint();
  243.         }
  244.     }
  245.  
  246.     /**
  247.      * Returns the current glass pane for this JRootPane.
  248.      * @return the current glass pane.
  249.      */
  250.     public Component getGlassPane() { 
  251.         return glassPane; 
  252.     }
  253.  
  254.  
  255.     /**
  256.      * Sets the current default button for this JRootPane.
  257.      * The default button is the button which will be activated 
  258.      * when a UI-defined activation event (typically the <Enter> key) 
  259.      * occurs in the RootPane regardless of whether or not the button 
  260.      * has keyboard focus (unless there is another component within 
  261.      * the RootPane which consumes the activation event, such as a JTextPane).
  262.      * For default activation to work, the button must be an enabled
  263.      * descendent of the RootPane when activation occurs.
  264.      * To remove a default button from this RootPane, set this
  265.      * property to null.
  266.      *
  267.      * @see JButton#isDefaultButton 
  268.      * @param default the default button.
  269.      */
  270.     public void setDefaultButton(JButton defaultButton) { 
  271.         JButton oldDefault = this.defaultButton;
  272.  
  273.         this.defaultButton = defaultButton;
  274.         if (defaultPressAction == null) {
  275.             defaultPressAction = new DefaultAction(this, true);
  276.             defaultReleaseAction = new DefaultAction(this, false);
  277.             // Eventually we should get the KeyStroke from the UI
  278.             // but hardcode it for now....
  279.             registerKeyboardAction(defaultPressAction, 
  280.                                    KeyStroke.getKeyStroke('\n', 0, false), 
  281.                    JComponent.WHEN_IN_FOCUSED_WINDOW);
  282.             registerKeyboardAction(defaultReleaseAction, 
  283.                                    KeyStroke.getKeyStroke('\n', 0, true), 
  284.                    JComponent.WHEN_IN_FOCUSED_WINDOW);
  285.         }
  286.         if (oldDefault != defaultButton) {
  287.             defaultPressAction.setOwner(defaultButton);
  288.             defaultReleaseAction.setOwner(defaultButton);
  289.  
  290.             if (oldDefault != null) {
  291.                 oldDefault.repaint();
  292.             }
  293.             if (defaultButton != null) {
  294.                 defaultButton.repaint();
  295.             }
  296.         }
  297.  
  298.         firePropertyChange("defaultButton", oldDefault, defaultButton);        
  299.     }
  300.  
  301.     /**
  302.      * Returns the current default button for this JRootPane.
  303.      * @return the current default button.
  304.      */
  305.     public JButton getDefaultButton() { 
  306.         return defaultButton;
  307.     }
  308.  
  309.     static class DefaultAction extends AbstractAction {
  310.         JButton owner;
  311.         JRootPane root;
  312.         boolean press;
  313.         DefaultAction(JRootPane root, boolean press) {
  314.         super(press? "pressedAction" : "releasedAction");
  315.             this.root = root;
  316.             this.press = press;
  317.     }
  318.         public void setOwner(JButton owner) {
  319.             this.owner = owner;
  320.         }
  321.     public void actionPerformed(ActionEvent e) {
  322.             if (owner != null && SwingUtilities.getRootPane(owner) == root) {
  323.             ButtonModel model = owner.getModel();
  324.                 if (press) {
  325.                 model.setArmed(true);
  326.                 model.setPressed(true);
  327.                 } else {
  328.                     model.setPressed(false);
  329.                 }
  330.             }
  331.         }
  332.     public boolean isEnabled() {
  333.         return owner.getModel().isEnabled();
  334.     }
  335.     }
  336.  
  337.  
  338.     /** Overridden to enforce the position of the glass component as the zero child. */
  339.     protected void addImpl(Component comp, Object constraints, int index) {
  340.         super.addImpl(comp, constraints, index);
  341.         
  342.         /// We are making sure the glassPane is on top. 
  343.         if(glassPane != null 
  344.             && glassPane.getParent() == this
  345.             && getComponent(0) != glassPane) {
  346.             add(glassPane, 0);
  347.         }
  348.     }
  349.  
  350. ///////////////////////////////////////////////////////////////////////////////
  351. //// Begin Inner Classes
  352. ///////////////////////////////////////////////////////////////////////////////
  353.  
  354.  
  355.     /** Responsible for Layout of layeredPane, glassPane, menuBar.
  356.      * <p>
  357.      * Warning: serialized objects of this class will not be compatible with
  358.      * future swing releases.  The current serialization support is appropriate
  359.      * for short term storage or RMI between Swing1.0 applications.  It will
  360.      * not be possible to load serialized Swing1.0 objects with future releases
  361.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  362.      * baseline for the serialized form of Swing objects.
  363.      */
  364.     protected class RootLayout implements LayoutManager2, Serializable
  365.     {
  366.  
  367.         public Dimension preferredLayoutSize(Container parent) {
  368.             Dimension rd, mbd;
  369.             Insets i = getInsets();
  370.         
  371.             if(contentPane != null) {
  372.                 rd = contentPane.getPreferredSize();
  373.             } else {
  374.                 rd = parent.getSize();
  375.             }
  376.             if(menuBar != null) {
  377.                 mbd = menuBar.getPreferredSize();
  378.             } else {
  379.                 mbd = new Dimension(0, 0);
  380.             }
  381.             return new Dimension(Math.max(rd.width, mbd.width) + i.left + i.right, 
  382.                                         rd.height + mbd.height + i.top + i.bottom);
  383.         }
  384.  
  385.         public Dimension minimumLayoutSize(Container parent) {
  386.             Dimension rd, mbd;
  387.             Insets i = getInsets();
  388.             if(contentPane != null) {
  389.                 rd = contentPane.getMinimumSize();
  390.             } else {
  391.                 rd = parent.getSize();
  392.             }
  393.             if(menuBar != null) {
  394.                 mbd = menuBar.getMinimumSize();
  395.             } else {
  396.                 mbd = new Dimension(0, 0);
  397.             }
  398.             return new Dimension(Math.max(rd.width, mbd.width) + i.left + i.right, 
  399.                         rd.height + mbd.height + i.top + i.bottom);
  400.         }
  401.  
  402.         public Dimension maximumLayoutSize(Container target) {
  403.             Dimension rd, mbd;
  404.             Insets i = getInsets();
  405.             if(menuBar != null) {
  406.                 mbd = menuBar.getMaximumSize();
  407.             } else {
  408.                 mbd = new Dimension(0, 0);
  409.             }
  410.             if(contentPane != null) {
  411.                 rd = contentPane.getMaximumSize();
  412.             } else {
  413.                 // This is silly, but should stop an overflow error
  414.                 rd = new Dimension(Integer.MAX_VALUE, 
  415.                         Integer.MAX_VALUE - i.top - i.bottom - mbd.height - 1);
  416.             }
  417.             return new Dimension(Math.min(rd.width, mbd.width) + i.left + i.right,
  418.                                          rd.height + mbd.height + i.top + i.bottom);
  419.         }
  420.         
  421.         public void layoutContainer(Container parent) {
  422.             Rectangle b = parent.getBounds();
  423.             Insets i = getInsets();
  424.             int contentY = 0;
  425.             int w = b.width - i.right - i.left;
  426.             int h = b.height - i.top - i.bottom;
  427.         
  428.             if(layeredPane != null) {
  429.                 layeredPane.setBounds(i.left, i.top, w, h);
  430.             }
  431.             if(glassPane != null) {
  432.                 glassPane.setBounds(i.left, i.top, w, h);
  433.             }
  434.             // Note: This is laying out the children in the layeredPane,
  435.             // technically, these are not our chilren.
  436.             if(menuBar != null) {
  437.                 Dimension mbd = menuBar.getPreferredSize();
  438.                 menuBar.setBounds(0, 0, w, mbd.height);
  439.                 contentY += mbd.height;
  440.             }
  441.             if(contentPane != null) {
  442.                 contentPane.setBounds(0, contentY, w, h - contentY);
  443.             }
  444.         }
  445.         
  446.         public void addLayoutComponent(String name, Component comp) {}
  447.         public void removeLayoutComponent(Component comp) {}
  448.         public void addLayoutComponent(Component comp, Object constraints) {}
  449.         public float getLayoutAlignmentX(Container target) { return 0.0f; }
  450.         public float getLayoutAlignmentY(Container target) { return 0.0f; }
  451.         public void invalidateLayout(Container target) {}
  452.     }
  453.  
  454. /////////////////
  455. // Accessibility support
  456. ////////////////
  457.  
  458.     /**
  459.      * Get the AccessibleContext associated with this JComponent
  460.      *
  461.      * @return the AccessibleContext of this JComponent
  462.      */
  463.     public AccessibleContext getAccessibleContext() {
  464.         if (accessibleContext == null) {
  465.             accessibleContext = new AccessibleJRootPane();
  466.         }
  467.         return accessibleContext;
  468.     }
  469.  
  470.     /**
  471.      * The class used to obtain the accessible role for this object.
  472.      * <p>
  473.      * Warning: serialized objects of this class will not be compatible with
  474.      * future swing releases.  The current serialization support is appropriate
  475.      * for short term storage or RMI between Swing1.0 applications.  It will
  476.      * not be possible to load serialized Swing1.0 objects with future releases
  477.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  478.      * baseline for the serialized form of Swing objects.
  479.      */
  480.     protected class AccessibleJRootPane extends AccessibleJComponent {
  481.         /**
  482.          * Get the role of this object.
  483.          *
  484.          * @return an instance of AccessibleRole describing the role of 
  485.          * the object
  486.          */
  487.         public AccessibleRole getAccessibleRole() {
  488.             return AccessibleRole.ROOT_PANE;
  489.         }
  490.     } // inner class AccessibleJRootPane
  491.  
  492. }
  493.