JRootPane.java revision 17230:6e591955c8a8
1/*
2 * Copyright (c) 1997, 2017, 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 */
25package javax.swing;
26
27import java.applet.Applet;
28import java.awt.*;
29import java.awt.event.*;
30import java.beans.*;
31import java.security.AccessController;
32import javax.accessibility.*;
33import javax.swing.plaf.RootPaneUI;
34import java.util.Vector;
35import java.io.Serializable;
36import javax.swing.border.*;
37
38import sun.awt.AWTAccessor;
39import sun.security.action.GetBooleanAction;
40
41
42/**
43 * A lightweight container used behind the scenes by
44 * <code>JFrame</code>, <code>JDialog</code>, <code>JWindow</code>,
45 * <code>JApplet</code>, and <code>JInternalFrame</code>.
46 * For task-oriented information on functionality provided by root panes
47 * see <a href="http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html">How to Use Root Panes</a>,
48 * a section in <em>The Java Tutorial</em>.
49 *
50 * <p>
51 * The following image shows the relationships between
52 * the classes that use root panes.
53 * <p style="text-align:center"><img src="doc-files/JRootPane-1.gif"
54 * alt="The following text describes this graphic."
55 * HEIGHT=484 WIDTH=629></p>
56 * The &quot;heavyweight&quot; components (those that delegate to a peer, or native
57 * component on the host system) are shown with a darker, heavier box. The four
58 * heavyweight JFC/Swing containers (<code>JFrame</code>, <code>JDialog</code>,
59 * <code>JWindow</code>, and <code>JApplet</code>) are
60 * shown in relation to the AWT classes they extend.
61 * These four components are the
62 * only heavyweight containers in the Swing library. The lightweight container
63 * <code>JInternalFrame</code> is also shown.
64 * All five of these JFC/Swing containers implement the
65 * <code>RootPaneContainer</code> interface,
66 * and they all delegate their operations to a
67 * <code>JRootPane</code> (shown with a little "handle" on top).
68 * <blockquote>
69 * <b>Note:</b> The <code>JComponent</code> method <code>getRootPane</code>
70 * can be used to obtain the <code>JRootPane</code> that contains
71 * a given component.
72 * </blockquote>
73 *
74 * <table class="borderless" style="float:right">
75 * <caption>Example</caption>
76 * <tr>
77 * <td style="text-align:center">
78 * <img src="doc-files/JRootPane-2.gif"
79 * alt="The following text describes this graphic." HEIGHT=386 WIDTH=349>
80 * </td>
81 * </tr>
82 * </table>
83 * The diagram at right shows the structure of a <code>JRootPane</code>.
84 * A <code>JRootpane</code> is made up of a <code>glassPane</code>,
85 * an optional <code>menuBar</code>, and a <code>contentPane</code>.
86 * (The <code>JLayeredPane</code> manages the <code>menuBar</code>
87 * and the <code>contentPane</code>.)
88 * The <code>glassPane</code> sits over the top of everything,
89 * where it is in a position to intercept mouse movements.
90 * Since the <code>glassPane</code> (like the <code>contentPane</code>)
91 * can be an arbitrary component, it is also possible to set up the
92 * <code>glassPane</code> for drawing. Lines and images on the
93 * <code>glassPane</code> can then range
94 * over the frames underneath without being limited by their boundaries.
95 * <p>
96 * Although the <code>menuBar</code> component is optional,
97 * the <code>layeredPane</code>, <code>contentPane</code>,
98 * and <code>glassPane</code> always exist.
99 * Attempting to set them to <code>null</code> generates an exception.
100 * <p>
101 * To add components to the <code>JRootPane</code> (other than the
102 * optional menu bar), you add the object to the <code>contentPane</code>
103 * of the <code>JRootPane</code>, like this:
104 * <pre>
105 *       rootPane.getContentPane().add(child);
106 * </pre>
107 * The same principle holds true for setting layout managers, removing
108 * components, listing children, etc. All these methods are invoked on
109 * the <code>contentPane</code> instead of on the <code>JRootPane</code>.
110 * <blockquote>
111 * <b>Note:</b> The default layout manager for the <code>contentPane</code> is
112 *  a <code>BorderLayout</code> manager. However, the <code>JRootPane</code>
113 *  uses a custom <code>LayoutManager</code>.
114 *  So, when you want to change the layout manager for the components you added
115 *  to a <code>JRootPane</code>, be sure to use code like this:
116 * <pre>
117 *    rootPane.getContentPane().setLayout(new BoxLayout());
118 * </pre></blockquote>
119 * If a <code>JMenuBar</code> component is set on the <code>JRootPane</code>,
120 * it is positioned along the upper edge of the frame.
121 * The <code>contentPane</code> is adjusted in location and size to
122 * fill the remaining area.
123 * (The <code>JMenuBar</code> and the <code>contentPane</code> are added to the
124 * <code>layeredPane</code> component at the
125 * <code>JLayeredPane.FRAME_CONTENT_LAYER</code> layer.)
126 * <p>
127 * The <code>layeredPane</code> is the parent of all children in the
128 * <code>JRootPane</code> -- both as the direct parent of the menu and
129 * the grandparent of all components added to the <code>contentPane</code>.
130 * It is an instance of <code>JLayeredPane</code>,
131 * which provides the ability to add components at several layers.
132 * This capability is very useful when working with menu popups,
133 * dialog boxes, and dragging -- situations in which you need to place
134 * a component on top of all other components in the pane.
135 * <p>
136 * The <code>glassPane</code> sits on top of all other components in the
137 * <code>JRootPane</code>.
138 * That provides a convenient place to draw above all other components,
139 * and makes it possible to intercept mouse events,
140 * which is useful both for dragging and for drawing.
141 * Developers can use <code>setVisible</code> on the <code>glassPane</code>
142 * to control when the <code>glassPane</code> displays over the other children.
143 * By default the <code>glassPane</code> is not visible.
144 * <p>
145 * The custom <code>LayoutManager</code> used by <code>JRootPane</code>
146 * ensures that:
147 * <OL>
148 * <LI>The <code>glassPane</code> fills the entire viewable
149 *     area of the <code>JRootPane</code> (bounds - insets).
150 * <LI>The <code>layeredPane</code> fills the entire viewable area of the
151 *     <code>JRootPane</code>. (bounds - insets)
152 * <LI>The <code>menuBar</code> is positioned at the upper edge of the
153 *     <code>layeredPane</code>.
154 * <LI>The <code>contentPane</code> fills the entire viewable area,
155 *     minus the <code>menuBar</code>, if present.
156 * </OL>
157 * Any other views in the <code>JRootPane</code> view hierarchy are ignored.
158 * <p>
159 * If you replace the <code>LayoutManager</code> of the <code>JRootPane</code>,
160 * you are responsible for managing all of these views.
161 * So ordinarily you will want to be sure that you
162 * change the layout manager for the <code>contentPane</code> rather than
163 * for the <code>JRootPane</code> itself!
164 * <p>
165 * The painting architecture of Swing requires an opaque
166 * <code>JComponent</code>
167 * to exist in the containment hierarchy above all other components. This is
168 * typically provided by way of the content pane. If you replace the content
169 * pane, it is recommended that you make the content pane opaque
170 * by way of <code>setOpaque(true)</code>. Additionally, if the content pane
171 * overrides <code>paintComponent</code>, it
172 * will need to completely fill in the background in an opaque color in
173 * <code>paintComponent</code>.
174 * <p>
175 * <strong>Warning:</strong> Swing is not thread safe. For more
176 * information see <a
177 * href="package-summary.html#threading">Swing's Threading
178 * Policy</a>.
179 * <p>
180 * <strong>Warning:</strong>
181 * Serialized objects of this class will not be compatible with
182 * future Swing releases. The current serialization support is
183 * appropriate for short term storage or RMI between applications running
184 * the same version of Swing.  As of 1.4, support for long term storage
185 * of all JavaBeans&trade;
186 * has been added to the <code>java.beans</code> package.
187 * Please see {@link java.beans.XMLEncoder}.
188 *
189 * @see JLayeredPane
190 * @see JMenuBar
191 * @see JWindow
192 * @see JFrame
193 * @see JDialog
194 * @see JApplet
195 * @see JInternalFrame
196 * @see JComponent
197 * @see BoxLayout
198 *
199 * @see <a href="http://www.oracle.com/technetwork/articles/java/mixing-components-433992.html">
200 * Mixing Heavy and Light Components</a>
201 *
202 * @author David Kloba
203 * @since 1.2
204 */
205/// PENDING(klobad) Who should be opaque in this component?
206@SuppressWarnings("serial")
207public class JRootPane extends JComponent implements Accessible {
208
209    private static final String uiClassID = "RootPaneUI";
210
211    /**
212     * Whether or not we should dump the stack when true double buffering
213     * is disabled. Default is false.
214     */
215    private static final boolean LOG_DISABLE_TRUE_DOUBLE_BUFFERING;
216
217    /**
218     * Whether or not we should ignore requests to disable true double
219     * buffering. Default is false.
220     */
221    private static final boolean IGNORE_DISABLE_TRUE_DOUBLE_BUFFERING;
222
223    /**
224     * Constant used for the windowDecorationStyle property. Indicates that
225     * the <code>JRootPane</code> should not provide any sort of
226     * Window decorations.
227     *
228     * @since 1.4
229     */
230    public static final int NONE = 0;
231
232    /**
233     * Constant used for the windowDecorationStyle property. Indicates that
234     * the <code>JRootPane</code> should provide decorations appropriate for
235     * a Frame.
236     *
237     * @since 1.4
238     */
239    public static final int FRAME = 1;
240
241    /**
242     * Constant used for the windowDecorationStyle property. Indicates that
243     * the <code>JRootPane</code> should provide decorations appropriate for
244     * a Dialog.
245     *
246     * @since 1.4
247     */
248    public static final int PLAIN_DIALOG = 2;
249
250    /**
251     * Constant used for the windowDecorationStyle property. Indicates that
252     * the <code>JRootPane</code> should provide decorations appropriate for
253     * a Dialog used to display an informational message.
254     *
255     * @since 1.4
256     */
257    public static final int INFORMATION_DIALOG = 3;
258
259    /**
260     * Constant used for the windowDecorationStyle property. Indicates that
261     * the <code>JRootPane</code> should provide decorations appropriate for
262     * a Dialog used to display an error message.
263     *
264     * @since 1.4
265     */
266    public static final int ERROR_DIALOG = 4;
267
268    /**
269     * Constant used for the windowDecorationStyle property. Indicates that
270     * the <code>JRootPane</code> should provide decorations appropriate for
271     * a Dialog used to display a <code>JColorChooser</code>.
272     *
273     * @since 1.4
274     */
275    public static final int COLOR_CHOOSER_DIALOG = 5;
276
277    /**
278     * Constant used for the windowDecorationStyle property. Indicates that
279     * the <code>JRootPane</code> should provide decorations appropriate for
280     * a Dialog used to display a <code>JFileChooser</code>.
281     *
282     * @since 1.4
283     */
284    public static final int FILE_CHOOSER_DIALOG = 6;
285
286    /**
287     * Constant used for the windowDecorationStyle property. Indicates that
288     * the <code>JRootPane</code> should provide decorations appropriate for
289     * a Dialog used to present a question to the user.
290     *
291     * @since 1.4
292     */
293    public static final int QUESTION_DIALOG = 7;
294
295    /**
296     * Constant used for the windowDecorationStyle property. Indicates that
297     * the <code>JRootPane</code> should provide decorations appropriate for
298     * a Dialog used to display a warning message.
299     *
300     * @since 1.4
301     */
302    public static final int WARNING_DIALOG = 8;
303
304    private int windowDecorationStyle;
305
306    /** The menu bar. */
307    protected JMenuBar menuBar;
308
309    /** The content pane. */
310    protected Container contentPane;
311
312    /** The layered pane that manages the menu bar and content pane. */
313    protected JLayeredPane layeredPane;
314
315    /**
316     * The glass pane that overlays the menu bar and content pane,
317     *  so it can intercept mouse movements and such.
318     */
319    protected Component glassPane;
320    /**
321     * The button that gets activated when the pane has the focus and
322     * a UI-specific action like pressing the <b>Enter</b> key occurs.
323     */
324    protected JButton defaultButton;
325
326    /**
327     * Whether or not true double buffering should be used.  This is typically
328     * true, but may be set to false in special situations.  For example,
329     * heavy weight popups (backed by a window) set this to false.
330     */
331    boolean useTrueDoubleBuffering = true;
332
333    static {
334        LOG_DISABLE_TRUE_DOUBLE_BUFFERING =
335            AccessController.doPrivileged(new GetBooleanAction(
336                                   "swing.logDoubleBufferingDisable"));
337        IGNORE_DISABLE_TRUE_DOUBLE_BUFFERING =
338            AccessController.doPrivileged(new GetBooleanAction(
339                                   "swing.ignoreDoubleBufferingDisable"));
340    }
341
342    /**
343     * Creates a <code>JRootPane</code>, setting up its
344     * <code>glassPane</code>, <code>layeredPane</code>,
345     * and <code>contentPane</code>.
346     */
347    public JRootPane() {
348        setGlassPane(createGlassPane());
349        setLayeredPane(createLayeredPane());
350        setContentPane(createContentPane());
351        setLayout(createRootLayout());
352        setDoubleBuffered(true);
353        updateUI();
354    }
355
356    /**
357     * {@inheritDoc}
358     * @since 1.6
359     */
360    public void setDoubleBuffered(boolean aFlag) {
361        if (isDoubleBuffered() != aFlag) {
362            super.setDoubleBuffered(aFlag);
363            RepaintManager.currentManager(this).doubleBufferingChanged(this);
364        }
365    }
366
367    /**
368     * Returns a constant identifying the type of Window decorations the
369     * <code>JRootPane</code> is providing.
370     *
371     * @return One of <code>NONE</code>, <code>FRAME</code>,
372     *        <code>PLAIN_DIALOG</code>, <code>INFORMATION_DIALOG</code>,
373     *        <code>ERROR_DIALOG</code>, <code>COLOR_CHOOSER_DIALOG</code>,
374     *        <code>FILE_CHOOSER_DIALOG</code>, <code>QUESTION_DIALOG</code> or
375     *        <code>WARNING_DIALOG</code>.
376     * @see #setWindowDecorationStyle
377     * @since 1.4
378     */
379    public int getWindowDecorationStyle() {
380        return windowDecorationStyle;
381    }
382
383    /**
384     * Sets the type of Window decorations (such as borders, widgets for
385     * closing a Window, title ...) the <code>JRootPane</code> should
386     * provide. The default is to provide no Window decorations
387     * (<code>NONE</code>).
388     * <p>
389     * This is only a hint, and some look and feels may not support
390     * this.
391     * This is a bound property.
392     *
393     * @param windowDecorationStyle Constant identifying Window decorations
394     *        to provide.
395     * @see JDialog#setDefaultLookAndFeelDecorated
396     * @see JFrame#setDefaultLookAndFeelDecorated
397     * @see LookAndFeel#getSupportsWindowDecorations
398     * @throws IllegalArgumentException if <code>style</code> is
399     *        not one of: <code>NONE</code>, <code>FRAME</code>,
400     *        <code>PLAIN_DIALOG</code>, <code>INFORMATION_DIALOG</code>,
401     *        <code>ERROR_DIALOG</code>, <code>COLOR_CHOOSER_DIALOG</code>,
402     *        <code>FILE_CHOOSER_DIALOG</code>, <code>QUESTION_DIALOG</code>, or
403     *        <code>WARNING_DIALOG</code>.
404     * @since 1.4
405     */
406    @BeanProperty(expert = true, visualUpdate = true, enumerationValues = {
407            "JRootPane.NONE",
408            "JRootPane.FRAME",
409            "JRootPane.PLAIN_DIALOG",
410            "JRootPane.INFORMATION_DIALOG",
411            "JRootPane.ERROR_DIALOG",
412            "JRootPane.COLOR_CHOOSER_DIALOG",
413            "JRootPane.FILE_CHOOSER_DIALOG",
414            "JRootPane.QUESTION_DIALOG",
415            "JRootPane.WARNING_DIALOG"}, description
416            = "Identifies the type of Window decorations to provide")
417    public void setWindowDecorationStyle(int windowDecorationStyle) {
418        if (windowDecorationStyle < 0 ||
419                  windowDecorationStyle > WARNING_DIALOG) {
420            throw new IllegalArgumentException("Invalid decoration style");
421        }
422        int oldWindowDecorationStyle = getWindowDecorationStyle();
423        this.windowDecorationStyle = windowDecorationStyle;
424        firePropertyChange("windowDecorationStyle",
425                            oldWindowDecorationStyle,
426                            windowDecorationStyle);
427    }
428
429    /**
430     * Returns the L&amp;F object that renders this component.
431     *
432     * @return <code>LabelUI</code> object
433     * @since 1.3
434     */
435    public RootPaneUI getUI() {
436        return (RootPaneUI)ui;
437    }
438
439    /**
440     * Sets the L&amp;F object that renders this component.
441     *
442     * @param ui  the <code>LabelUI</code> L&amp;F object
443     * @see UIDefaults#getUI
444     * @since 1.3
445     */
446    @BeanProperty(expert = true, hidden = true, visualUpdate = true, description
447            = "The UI object that implements the Component's LookAndFeel.")
448    public void setUI(RootPaneUI ui) {
449        super.setUI(ui);
450    }
451
452
453    /**
454     * Resets the UI property to a value from the current look and feel.
455     *
456     * @see JComponent#updateUI
457     */
458    public void updateUI() {
459        setUI((RootPaneUI)UIManager.getUI(this));
460    }
461
462
463    /**
464     * Returns a string that specifies the name of the L&amp;F class
465     * that renders this component.
466     *
467     * @return the string "RootPaneUI"
468     *
469     * @see JComponent#getUIClassID
470     * @see UIDefaults#getUI
471     */
472    public String getUIClassID() {
473        return uiClassID;
474    }
475
476    /**
477      * Called by the constructor methods to create the default
478      * <code>layeredPane</code>.
479      * Bt default it creates a new <code>JLayeredPane</code>.
480      * @return the default <code>layeredPane</code>
481      */
482    protected JLayeredPane createLayeredPane() {
483        JLayeredPane p = new JLayeredPane();
484        p.setName(this.getName()+".layeredPane");
485        return p;
486    }
487
488    /**
489     * Called by the constructor methods to create the default
490     * <code>contentPane</code>.
491     * By default this method creates a new <code>JComponent</code> add sets a
492     * <code>BorderLayout</code> as its <code>LayoutManager</code>.
493     * @return the default <code>contentPane</code>
494     */
495    protected Container createContentPane() {
496        JComponent c = new JPanel();
497        c.setName(this.getName()+".contentPane");
498        c.setLayout(new BorderLayout() {
499            /* This BorderLayout subclass maps a null constraint to CENTER.
500             * Although the reference BorderLayout also does this, some VMs
501             * throw an IllegalArgumentException.
502             */
503            public void addLayoutComponent(Component comp, Object constraints) {
504                if (constraints == null) {
505                    constraints = BorderLayout.CENTER;
506                }
507                super.addLayoutComponent(comp, constraints);
508            }
509        });
510        return c;
511    }
512
513    /**
514      * Called by the constructor methods to create the default
515      * <code>glassPane</code>.
516      * By default this method creates a new <code>JComponent</code>
517      * with visibility set to false.
518      * @return the default <code>glassPane</code>
519      */
520    protected Component createGlassPane() {
521        JComponent c = new JPanel();
522        c.setName(this.getName()+".glassPane");
523        c.setVisible(false);
524        ((JPanel)c).setOpaque(false);
525        return c;
526    }
527
528    /**
529     * Called by the constructor methods to create the default
530     * <code>layoutManager</code>.
531     * @return the default <code>layoutManager</code>.
532     */
533    protected LayoutManager createRootLayout() {
534        return new RootLayout();
535    }
536
537    /**
538     * Adds or changes the menu bar used in the layered pane.
539     * @param menu the <code>JMenuBar</code> to add
540     */
541    public void setJMenuBar(JMenuBar menu) {
542        if(menuBar != null && menuBar.getParent() == layeredPane)
543            layeredPane.remove(menuBar);
544        menuBar = menu;
545
546        if(menuBar != null) {
547            menuBar.updateUI();
548            layeredPane.add(menuBar, JLayeredPane.FRAME_CONTENT_LAYER);
549        }
550    }
551
552    /**
553     * Specifies the menu bar value.
554     * @deprecated As of Swing version 1.0.3
555     *  replaced by <code>setJMenuBar(JMenuBar menu)</code>.
556     * @param menu the <code>JMenuBar</code> to add.
557     */
558    @Deprecated
559    public void setMenuBar(JMenuBar menu){
560        if(menuBar != null && menuBar.getParent() == layeredPane)
561            layeredPane.remove(menuBar);
562        menuBar = menu;
563
564        if(menuBar != null)
565            layeredPane.add(menuBar, JLayeredPane.FRAME_CONTENT_LAYER);
566    }
567
568    /**
569     * Returns the menu bar from the layered pane.
570     * @return the <code>JMenuBar</code> used in the pane
571     */
572    public JMenuBar getJMenuBar() { return menuBar; }
573
574    /**
575     * Returns the menu bar value.
576     * @deprecated As of Swing version 1.0.3
577     *  replaced by <code>getJMenuBar()</code>.
578     * @return the <code>JMenuBar</code> used in the pane
579     */
580    @Deprecated
581    public JMenuBar getMenuBar() { return menuBar; }
582
583    /**
584     * Sets the content pane -- the container that holds the components
585     * parented by the root pane.
586     * <p>
587     * Swing's painting architecture requires an opaque <code>JComponent</code>
588     * in the containment hierarchy. This is typically provided by the
589     * content pane. If you replace the content pane it is recommended you
590     * replace it with an opaque <code>JComponent</code>.
591     *
592     * @param content the <code>Container</code> to use for component-contents
593     * @exception java.awt.IllegalComponentStateException (a runtime
594     *            exception) if the content pane parameter is <code>null</code>
595     */
596    public void setContentPane(Container content) {
597        if(content == null)
598            throw new IllegalComponentStateException("contentPane cannot be set to null.");
599        if(contentPane != null && contentPane.getParent() == layeredPane)
600            layeredPane.remove(contentPane);
601        contentPane = content;
602
603        layeredPane.add(contentPane, JLayeredPane.FRAME_CONTENT_LAYER);
604    }
605
606    /**
607     * Returns the content pane -- the container that holds the components
608     * parented by the root pane.
609     *
610     * @return the <code>Container</code> that holds the component-contents
611     */
612    public Container getContentPane() { return contentPane; }
613
614// PENDING(klobad) Should this reparent the contentPane and MenuBar?
615    /**
616     * Sets the layered pane for the root pane. The layered pane
617     * typically holds a content pane and an optional <code>JMenuBar</code>.
618     *
619     * @param layered  the <code>JLayeredPane</code> to use
620     * @exception java.awt.IllegalComponentStateException (a runtime
621     *            exception) if the layered pane parameter is <code>null</code>
622     */
623    public void setLayeredPane(JLayeredPane layered) {
624        if(layered == null)
625            throw new IllegalComponentStateException("layeredPane cannot be set to null.");
626        if(layeredPane != null && layeredPane.getParent() == this)
627            this.remove(layeredPane);
628        layeredPane = layered;
629
630        this.add(layeredPane, -1);
631    }
632    /**
633     * Gets the layered pane used by the root pane. The layered pane
634     * typically holds a content pane and an optional <code>JMenuBar</code>.
635     *
636     * @return the <code>JLayeredPane</code> currently in use
637     */
638    public JLayeredPane getLayeredPane() { return layeredPane; }
639
640    /**
641     * Sets a specified <code>Component</code> to be the glass pane for this
642     * root pane.  The glass pane should normally be a lightweight,
643     * transparent component, because it will be made visible when
644     * ever the root pane needs to grab input events.
645     * <p>
646     * The new glass pane's visibility is changed to match that of
647     * the current glass pane.  An implication of this is that care
648     * must be taken when you want to replace the glass pane and
649     * make it visible.  Either of the following will work:
650     * <pre>
651     *   root.setGlassPane(newGlassPane);
652     *   newGlassPane.setVisible(true);
653     * </pre>
654     * or:
655     * <pre>
656     *   root.getGlassPane().setVisible(true);
657     *   root.setGlassPane(newGlassPane);
658     * </pre>
659     *
660     * @param glass the <code>Component</code> to use as the glass pane
661     *              for this <code>JRootPane</code>
662     * @exception NullPointerException if the <code>glass</code> parameter is
663     *          <code>null</code>
664     */
665    public void setGlassPane(Component glass) {
666        if (glass == null) {
667            throw new NullPointerException("glassPane cannot be set to null.");
668        }
669
670        glass.setMixingCutoutShape(new Rectangle());
671
672        boolean visible = false;
673        if (glassPane != null && glassPane.getParent() == this) {
674            this.remove(glassPane);
675            visible = glassPane.isVisible();
676        }
677
678        glass.setVisible(visible);
679        glassPane = glass;
680        this.add(glassPane, 0);
681        if (visible) {
682            repaint();
683        }
684    }
685
686    /**
687     * Returns the current glass pane for this <code>JRootPane</code>.
688     * @return the current glass pane
689     * @see #setGlassPane
690     */
691    public Component getGlassPane() {
692        return glassPane;
693    }
694
695    /**
696     * If a descendant of this <code>JRootPane</code> calls
697     * <code>revalidate</code>, validate from here on down.
698     *<p>
699     * Deferred requests to layout a component and its descendents again.
700     * For example, calls to <code>revalidate</code>, are pushed upwards to
701     * either a <code>JRootPane</code> or a <code>JScrollPane</code>
702     * because both classes override <code>isValidateRoot</code> to return true.
703     *
704     * @see JComponent#isValidateRoot
705     * @see java.awt.Container#isValidateRoot
706     * @return true
707     */
708    @Override
709    public boolean isValidateRoot() {
710        return true;
711    }
712
713    /**
714     * The <code>glassPane</code> and <code>contentPane</code>
715     * have the same bounds, which means <code>JRootPane</code>
716     * does not tiles its children and this should return false.
717     * On the other hand, the <code>glassPane</code>
718     * is normally not visible, and so this can return true if the
719     * <code>glassPane</code> isn't visible. Therefore, the
720     * return value here depends upon the visibility of the
721     * <code>glassPane</code>.
722     *
723     * @return true if this component's children don't overlap
724     */
725    public boolean isOptimizedDrawingEnabled() {
726        return !glassPane.isVisible();
727    }
728
729    /**
730     * {@inheritDoc}
731     */
732    public void addNotify() {
733        super.addNotify();
734        enableEvents(AWTEvent.KEY_EVENT_MASK);
735    }
736
737    /**
738     * {@inheritDoc}
739     */
740    public void removeNotify() {
741        super.removeNotify();
742    }
743
744
745    /**
746     * Sets the <code>defaultButton</code> property,
747     * which determines the current default button for this <code>JRootPane</code>.
748     * The default button is the button which will be activated
749     * when a UI-defined activation event (typically the <b>Enter</b> key)
750     * occurs in the root pane regardless of whether or not the button
751     * has keyboard focus (unless there is another component within
752     * the root pane which consumes the activation event,
753     * such as a <code>JTextPane</code>).
754     * For default activation to work, the button must be an enabled
755     * descendent of the root pane when activation occurs.
756     * To remove a default button from this root pane, set this
757     * property to <code>null</code>.
758     *
759     * @see JButton#isDefaultButton
760     * @param defaultButton the <code>JButton</code> which is to be the default button
761     */
762    @BeanProperty(description
763            = "The button activated by default in this root pane")
764    public void setDefaultButton(JButton defaultButton) {
765        JButton oldDefault = this.defaultButton;
766
767        if (oldDefault != defaultButton) {
768            this.defaultButton = defaultButton;
769
770            if (oldDefault != null) {
771                oldDefault.repaint();
772            }
773            if (defaultButton != null) {
774                defaultButton.repaint();
775            }
776        }
777
778        firePropertyChange("defaultButton", oldDefault, defaultButton);
779    }
780
781    /**
782     * Returns the value of the <code>defaultButton</code> property.
783     * @return the <code>JButton</code> which is currently the default button
784     * @see #setDefaultButton
785     */
786    public JButton getDefaultButton() {
787        return defaultButton;
788    }
789
790    final void setUseTrueDoubleBuffering(boolean useTrueDoubleBuffering) {
791        this.useTrueDoubleBuffering = useTrueDoubleBuffering;
792    }
793
794    final boolean getUseTrueDoubleBuffering() {
795        return useTrueDoubleBuffering;
796    }
797
798    final void disableTrueDoubleBuffering() {
799        if (useTrueDoubleBuffering) {
800            if (!IGNORE_DISABLE_TRUE_DOUBLE_BUFFERING) {
801                if (LOG_DISABLE_TRUE_DOUBLE_BUFFERING) {
802                    System.out.println("Disabling true double buffering for " +
803                                       this);
804                    Thread.dumpStack();
805                }
806                useTrueDoubleBuffering = false;
807                RepaintManager.currentManager(this).
808                        doubleBufferingChanged(this);
809            }
810        }
811    }
812
813    /**
814     * Overridden to enforce the position of the glass component as
815     * the zero child.
816     *
817     * @param comp the component to be enhanced
818     * @param constraints the constraints to be respected
819     * @param index the index
820     */
821    protected void addImpl(Component comp, Object constraints, int index) {
822        super.addImpl(comp, constraints, index);
823
824        /// We are making sure the glassPane is on top.
825        if(glassPane != null
826            && glassPane.getParent() == this
827            && getComponent(0) != glassPane) {
828            add(glassPane, 0);
829        }
830    }
831
832
833///////////////////////////////////////////////////////////////////////////////
834//// Begin Inner Classes
835///////////////////////////////////////////////////////////////////////////////
836
837
838    /**
839     * A custom layout manager that is responsible for the layout of
840     * layeredPane, glassPane, and menuBar.
841     * <p>
842     * <strong>Warning:</strong>
843     * Serialized objects of this class will not be compatible with
844     * future Swing releases. The current serialization support is
845     * appropriate for short term storage or RMI between applications running
846     * the same version of Swing.  As of 1.4, support for long term storage
847     * of all JavaBeans&trade;
848     * has been added to the <code>java.beans</code> package.
849     * Please see {@link java.beans.XMLEncoder}.
850     */
851    @SuppressWarnings("serial")
852    protected class RootLayout implements LayoutManager2, Serializable
853    {
854        /**
855         * Returns the amount of space the layout would like to have.
856         *
857         * @param parent the Container for which this layout manager
858         * is being used
859         * @return a Dimension object containing the layout's preferred size
860         */
861        public Dimension preferredLayoutSize(Container parent) {
862            Dimension rd, mbd;
863            Insets i = getInsets();
864
865            if(contentPane != null) {
866                rd = contentPane.getPreferredSize();
867            } else {
868                rd = parent.getSize();
869            }
870            if(menuBar != null && menuBar.isVisible()) {
871                mbd = menuBar.getPreferredSize();
872            } else {
873                mbd = new Dimension(0, 0);
874            }
875            return new Dimension(Math.max(rd.width, mbd.width) + i.left + i.right,
876                                        rd.height + mbd.height + i.top + i.bottom);
877        }
878
879        /**
880         * Returns the minimum amount of space the layout needs.
881         *
882         * @param parent the Container for which this layout manager
883         * is being used
884         * @return a Dimension object containing the layout's minimum size
885         */
886        public Dimension minimumLayoutSize(Container parent) {
887            Dimension rd, mbd;
888            Insets i = getInsets();
889            if(contentPane != null) {
890                rd = contentPane.getMinimumSize();
891            } else {
892                rd = parent.getSize();
893            }
894            if(menuBar != null && menuBar.isVisible()) {
895                mbd = menuBar.getMinimumSize();
896            } else {
897                mbd = new Dimension(0, 0);
898            }
899            return new Dimension(Math.max(rd.width, mbd.width) + i.left + i.right,
900                        rd.height + mbd.height + i.top + i.bottom);
901        }
902
903        /**
904         * Returns the maximum amount of space the layout can use.
905         *
906         * @param target the Container for which this layout manager
907         * is being used
908         * @return a Dimension object containing the layout's maximum size
909         */
910        public Dimension maximumLayoutSize(Container target) {
911            Dimension rd, mbd;
912            Insets i = getInsets();
913            if(menuBar != null && menuBar.isVisible()) {
914                mbd = menuBar.getMaximumSize();
915            } else {
916                mbd = new Dimension(0, 0);
917            }
918            if(contentPane != null) {
919                rd = contentPane.getMaximumSize();
920            } else {
921                // This is silly, but should stop an overflow error
922                rd = new Dimension(Integer.MAX_VALUE,
923                        Integer.MAX_VALUE - i.top - i.bottom - mbd.height - 1);
924            }
925            return new Dimension(Math.min(rd.width, mbd.width) + i.left + i.right,
926                                         rd.height + mbd.height + i.top + i.bottom);
927        }
928
929        /**
930         * Instructs the layout manager to perform the layout for the specified
931         * container.
932         *
933         * @param parent the Container for which this layout manager
934         * is being used
935         */
936        public void layoutContainer(Container parent) {
937            Rectangle b = parent.getBounds();
938            Insets i = getInsets();
939            int contentY = 0;
940            int w = b.width - i.right - i.left;
941            int h = b.height - i.top - i.bottom;
942
943            if(layeredPane != null) {
944                layeredPane.setBounds(i.left, i.top, w, h);
945            }
946            if(glassPane != null) {
947                glassPane.setBounds(i.left, i.top, w, h);
948            }
949            // Note: This is laying out the children in the layeredPane,
950            // technically, these are not our children.
951            if(menuBar != null && menuBar.isVisible()) {
952                Dimension mbd = menuBar.getPreferredSize();
953                menuBar.setBounds(0, 0, w, mbd.height);
954                contentY += mbd.height;
955            }
956            if(contentPane != null) {
957                contentPane.setBounds(0, contentY, w, h - contentY);
958            }
959        }
960
961        public void addLayoutComponent(String name, Component comp) {}
962        public void removeLayoutComponent(Component comp) {}
963        public void addLayoutComponent(Component comp, Object constraints) {}
964        public float getLayoutAlignmentX(Container target) { return 0.0f; }
965        public float getLayoutAlignmentY(Container target) { return 0.0f; }
966        public void invalidateLayout(Container target) {}
967    }
968
969    /**
970     * Returns a string representation of this <code>JRootPane</code>.
971     * This method is intended to be used only for debugging purposes,
972     * and the content and format of the returned string may vary between
973     * implementations. The returned string may be empty but may not
974     * be <code>null</code>.
975     *
976     * @return  a string representation of this <code>JRootPane</code>.
977     */
978    protected String paramString() {
979        return super.paramString();
980    }
981
982/////////////////
983// Accessibility support
984////////////////
985
986    /**
987     * Gets the <code>AccessibleContext</code> associated with this
988     * <code>JRootPane</code>. For root panes, the
989     * <code>AccessibleContext</code> takes the form of an
990     * <code>AccessibleJRootPane</code>.
991     * A new <code>AccessibleJRootPane</code> instance is created if necessary.
992     *
993     * @return an <code>AccessibleJRootPane</code> that serves as the
994     *         <code>AccessibleContext</code> of this <code>JRootPane</code>
995     */
996    public AccessibleContext getAccessibleContext() {
997        if (accessibleContext == null) {
998            accessibleContext = new AccessibleJRootPane();
999        }
1000        return accessibleContext;
1001    }
1002
1003    /**
1004     * This class implements accessibility support for the
1005     * <code>JRootPane</code> class.  It provides an implementation of the
1006     * Java Accessibility API appropriate to root pane user-interface elements.
1007     * <p>
1008     * <strong>Warning:</strong>
1009     * Serialized objects of this class will not be compatible with
1010     * future Swing releases. The current serialization support is
1011     * appropriate for short term storage or RMI between applications running
1012     * the same version of Swing.  As of 1.4, support for long term storage
1013     * of all JavaBeans&trade;
1014     * has been added to the <code>java.beans</code> package.
1015     * Please see {@link java.beans.XMLEncoder}.
1016     */
1017    @SuppressWarnings("serial")
1018    protected class AccessibleJRootPane extends AccessibleJComponent {
1019        /**
1020         * Get the role of this object.
1021         *
1022         * @return an instance of AccessibleRole describing the role of
1023         * the object
1024         */
1025        public AccessibleRole getAccessibleRole() {
1026            return AccessibleRole.ROOT_PANE;
1027        }
1028
1029        /**
1030         * Returns the number of accessible children of the object.
1031         *
1032         * @return the number of accessible children of the object.
1033         */
1034        public int getAccessibleChildrenCount() {
1035            return super.getAccessibleChildrenCount();
1036        }
1037
1038        /**
1039         * Returns the specified Accessible child of the object.  The Accessible
1040         * children of an Accessible object are zero-based, so the first child
1041         * of an Accessible child is at index 0, the second child is at index 1,
1042         * and so on.
1043         *
1044         * @param i zero-based index of child
1045         * @return the Accessible child of the object
1046         * @see #getAccessibleChildrenCount
1047         */
1048        public Accessible getAccessibleChild(int i) {
1049            return super.getAccessibleChild(i);
1050        }
1051    } // inner class AccessibleJRootPane
1052}
1053