989 lines · 35.8 KB · Java
RawDownload
/* * Copyright (c) 2000, 2006, 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.plaf.metal; import java.awt.event.*;import java.beans.PropertyChangeEvent;import java.beans.PropertyChangeListener;import javax.swing.*;import javax.swing.border.*;import javax.swing.event.*;import javax.swing.plaf.*;import javax.swing.plaf.basic.*;import java.awt.*;import java.io.*;import java.security.*; /** * Provides the metal look and feel implementation of <code>RootPaneUI</code>. * <p> * <code>MetalRootPaneUI</code> provides support for the * <code>windowDecorationStyle</code> property of <code>JRootPane</code>. * <code>MetalRootPaneUI</code> does this by way of installing a custom * <code>LayoutManager</code>, a private <code>Component</code> to render * the appropriate widgets, and a private <code>Border</code>. The * <code>LayoutManager</code> is always installed, regardless of the value of * the <code>windowDecorationStyle</code> property, but the * <code>Border</code> and <code>Component</code> are only installed/added if * the <code>windowDecorationStyle</code> is other than * <code>JRootPane.NONE</code>. * <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<sup><font size="-2">TM</font></sup> * has been added to the <code>java.beans</code> package. * Please see {@link java.beans.XMLEncoder}. * * @author Terry Kellerman * @since 1.4 */public class MetalRootPaneUI extends BasicRootPaneUI{    /**     * Keys to lookup borders in defaults table.     */    private static final String[] borderKeys = new String[] {        null, "RootPane.frameBorder", "RootPane.plainDialogBorder",        "RootPane.informationDialogBorder",        "RootPane.errorDialogBorder", "RootPane.colorChooserDialogBorder",        "RootPane.fileChooserDialogBorder", "RootPane.questionDialogBorder",        "RootPane.warningDialogBorder"    };    /**     * The amount of space (in pixels) that the cursor is changed on.     */    private static final int CORNER_DRAG_WIDTH = 16;     /**     * Region from edges that dragging is active from.     */    private static final int BORDER_DRAG_THICKNESS = 5;     /**     * Window the <code>JRootPane</code> is in.     */    private Window window;     /**     * <code>JComponent</code> providing window decorations. This will be     * null if not providing window decorations.     */    private JComponent titlePane;     /**     * <code>MouseInputListener</code> that is added to the parent     * <code>Window</code> the <code>JRootPane</code> is contained in.     */    private MouseInputListener mouseInputListener;     /**     * The <code>LayoutManager</code> that is set on the     * <code>JRootPane</code>.     */    private LayoutManager layoutManager;     /**     * <code>LayoutManager</code> of the <code>JRootPane</code> before we     * replaced it.     */    private LayoutManager savedOldLayout;     /**     * <code>JRootPane</code> providing the look and feel for.     */    private JRootPane root;     /**     * <code>Cursor</code> used to track the cursor set by the user.     * This is initially <code>Cursor.DEFAULT_CURSOR</code>.     */    private Cursor lastCursor =            Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);     /**     * Creates a UI for a <code>JRootPane</code>.     *     * @param c the JRootPane the RootPaneUI will be created for     * @return the RootPaneUI implementation for the passed in JRootPane     */    public static ComponentUI createUI(JComponent c) {        return new MetalRootPaneUI();    }     /**     * Invokes supers implementation of <code>installUI</code> to install     * the necessary state onto the passed in <code>JRootPane</code>     * to render the metal look and feel implementation of     * <code>RootPaneUI</code>. If     * the <code>windowDecorationStyle</code> property of the     * <code>JRootPane</code> is other than <code>JRootPane.NONE</code>,     * this will add a custom <code>Component</code> to render the widgets to     * <code>JRootPane</code>, as well as installing a custom     * <code>Border</code> and <code>LayoutManager</code> on the     * <code>JRootPane</code>.     *     * @param c the JRootPane to install state onto     */    public void installUI(JComponent c) {        super.installUI(c);        root = (JRootPane)c;        int style = root.getWindowDecorationStyle();        if (style != JRootPane.NONE) {            installClientDecorations(root);        }    }      /**     * Invokes supers implementation to uninstall any of its state. This will     * also reset the <code>LayoutManager</code> of the <code>JRootPane</code>.     * If a <code>Component</code> has been added to the <code>JRootPane</code>     * to render the window decoration style, this method will remove it.     * Similarly, this will revert the Border and LayoutManager of the     * <code>JRootPane</code> to what it was before <code>installUI</code>     * was invoked.     *     * @param c the JRootPane to uninstall state from     */    public void uninstallUI(JComponent c) {        super.uninstallUI(c);        uninstallClientDecorations(root);         layoutManager = null;        mouseInputListener = null;        root = null;    }     /**     * Installs the appropriate <code>Border</code> onto the     * <code>JRootPane</code>.     */    void installBorder(JRootPane root) {        int style = root.getWindowDecorationStyle();         if (style == JRootPane.NONE) {            LookAndFeel.uninstallBorder(root);        }        else {            LookAndFeel.installBorder(root, borderKeys[style]);        }    }     /**     * Removes any border that may have been installed.     */    private void uninstallBorder(JRootPane root) {        LookAndFeel.uninstallBorder(root);    }     /**     * Installs the necessary Listeners on the parent <code>Window</code>,     * if there is one.     * <p>     * This takes the parent so that cleanup can be done from     * <code>removeNotify</code>, at which point the parent hasn't been     * reset yet.     *     * @param parent The parent of the JRootPane     */    private void installWindowListeners(JRootPane root, Component parent) {        if (parent instanceof Window) {            window = (Window)parent;        }        else {            window = SwingUtilities.getWindowAncestor(parent);        }        if (window != null) {            if (mouseInputListener == null) {                mouseInputListener = createWindowMouseInputListener(root);            }            window.addMouseListener(mouseInputListener);            window.addMouseMotionListener(mouseInputListener);        }    }     /**     * Uninstalls the necessary Listeners on the <code>Window</code> the     * Listeners were last installed on.     */    private void uninstallWindowListeners(JRootPane root) {        if (window != null) {            window.removeMouseListener(mouseInputListener);            window.removeMouseMotionListener(mouseInputListener);        }    }     /**     * Installs the appropriate LayoutManager on the <code>JRootPane</code>     * to render the window decorations.     */    private void installLayout(JRootPane root) {        if (layoutManager == null) {            layoutManager = createLayoutManager();        }        savedOldLayout = root.getLayout();        root.setLayout(layoutManager);    }     /**     * Uninstalls the previously installed <code>LayoutManager</code>.     */    private void uninstallLayout(JRootPane root) {        if (savedOldLayout != null) {            root.setLayout(savedOldLayout);            savedOldLayout = null;        }    }     /**     * Installs the necessary state onto the JRootPane to render client     * decorations. This is ONLY invoked if the <code>JRootPane</code>     * has a decoration style other than <code>JRootPane.NONE</code>.     */    private void installClientDecorations(JRootPane root) {        installBorder(root);         JComponent titlePane = createTitlePane(root);         setTitlePane(root, titlePane);        installWindowListeners(root, root.getParent());        installLayout(root);        if (window != null) {            root.revalidate();            root.repaint();        }    }     /**     * Uninstalls any state that <code>installClientDecorations</code> has     * installed.     * <p>     * NOTE: This may be called if you haven't installed client decorations     * yet (ie before <code>installClientDecorations</code> has been invoked).     */    private void uninstallClientDecorations(JRootPane root) {        uninstallBorder(root);        uninstallWindowListeners(root);        setTitlePane(root, null);        uninstallLayout(root);        // We have to revalidate/repaint root if the style is JRootPane.NONE        // only. When we needs to call revalidate/repaint with other styles        // the installClientDecorations is always called after this method        // imediatly and it will cause the revalidate/repaint at the proper        // time.        int style = root.getWindowDecorationStyle();        if (style == JRootPane.NONE) {            root.repaint();            root.revalidate();        }        // Reset the cursor, as we may have changed it to a resize cursor        if (window != null) {            window.setCursor(Cursor.getPredefinedCursor                             (Cursor.DEFAULT_CURSOR));        }        window = null;    }     /**     * Returns the <code>JComponent</code> to render the window decoration     * style.     */    private JComponent createTitlePane(JRootPane root) {        return new MetalTitlePane(root, this);    }     /**     * Returns a <code>MouseListener</code> that will be added to the     * <code>Window</code> containing the <code>JRootPane</code>.     */    private MouseInputListener createWindowMouseInputListener(JRootPane root) {        return new MouseInputHandler();    }     /**     * Returns a <code>LayoutManager</code> that will be set on the     * <code>JRootPane</code>.     */    private LayoutManager createLayoutManager() {        return new MetalRootLayout();    }     /**     * Sets the window title pane -- the JComponent used to provide a plaf a     * way to override the native operating system's window title pane with     * one whose look and feel are controlled by the plaf.  The plaf creates     * and sets this value; the default is null, implying a native operating     * system window title pane.     *     * @param content the <code>JComponent</code> to use for the window title pane.     */    private void setTitlePane(JRootPane root, JComponent titlePane) {        JLayeredPane layeredPane = root.getLayeredPane();        JComponent oldTitlePane = getTitlePane();         if (oldTitlePane != null) {            oldTitlePane.setVisible(false);            layeredPane.remove(oldTitlePane);        }        if (titlePane != null) {            layeredPane.add(titlePane, JLayeredPane.FRAME_CONTENT_LAYER);            titlePane.setVisible(true);        }        this.titlePane = titlePane;    }     /**     * Returns the <code>JComponent</code> rendering the title pane. If this     * returns null, it implies there is no need to render window decorations.     *     * @return the current window title pane, or null     * @see #setTitlePane     */    private JComponent getTitlePane() {        return titlePane;    }     /**     * Returns the <code>JRootPane</code> we're providing the look and     * feel for.     */    private JRootPane getRootPane() {        return root;    }     /**     * Invoked when a property changes. <code>MetalRootPaneUI</code> is     * primarily interested in events originating from the     * <code>JRootPane</code> it has been installed on identifying the     * property <code>windowDecorationStyle</code>. If the     * <code>windowDecorationStyle</code> has changed to a value other     * than <code>JRootPane.NONE</code>, this will add a <code>Component</code>     * to the <code>JRootPane</code> to render the window decorations, as well     * as installing a <code>Border</code> on the <code>JRootPane</code>.     * On the other hand, if the <code>windowDecorationStyle</code> has     * changed to <code>JRootPane.NONE</code>, this will remove the     * <code>Component</code> that has been added to the <code>JRootPane</code>     * as well resetting the Border to what it was before     * <code>installUI</code> was invoked.     *     * @param e A PropertyChangeEvent object describing the event source     *          and the property that has changed.     */    public void propertyChange(PropertyChangeEvent e) {        super.propertyChange(e);         String propertyName = e.getPropertyName();        if(propertyName == null) {            return;        }         if(propertyName.equals("windowDecorationStyle")) {            JRootPane root = (JRootPane) e.getSource();            int style = root.getWindowDecorationStyle();             // This is potentially more than needs to be done,            // but it rarely happens and makes the install/uninstall process            // simpler. MetalTitlePane also assumes it will be recreated if            // the decoration style changes.            uninstallClientDecorations(root);            if (style != JRootPane.NONE) {                installClientDecorations(root);            }        }        else if (propertyName.equals("ancestor")) {            uninstallWindowListeners(root);            if (((JRootPane)e.getSource()).getWindowDecorationStyle() !=                                           JRootPane.NONE) {                installWindowListeners(root, root.getParent());            }        }        return;    }     /**     * A custom layout manager that is responsible for the layout of     * layeredPane, glassPane, menuBar and titlePane, if one has been     * installed.     */    // NOTE: Ideally this would extends JRootPane.RootLayout, but that    //       would force this to be non-static.    private static class MetalRootLayout implements LayoutManager2 {        /**         * Returns the amount of space the layout would like to have.         *         * @param the Container for which this layout manager is being used         * @return a Dimension object containing the layout's preferred size         */        public Dimension preferredLayoutSize(Container parent) {            Dimension cpd, mbd, tpd;            int cpWidth = 0;            int cpHeight = 0;            int mbWidth = 0;            int mbHeight = 0;            int tpWidth = 0;            int tpHeight = 0;            Insets i = parent.getInsets();            JRootPane root = (JRootPane) parent;             if(root.getContentPane() != null) {                cpd = root.getContentPane().getPreferredSize();            } else {                cpd = root.getSize();            }            if (cpd != null) {                cpWidth = cpd.width;                cpHeight = cpd.height;            }             if(root.getMenuBar() != null) {                mbd = root.getMenuBar().getPreferredSize();                if (mbd != null) {                    mbWidth = mbd.width;                    mbHeight = mbd.height;                }            }             if (root.getWindowDecorationStyle() != JRootPane.NONE &&                     (root.getUI() instanceof MetalRootPaneUI)) {                JComponent titlePane = ((MetalRootPaneUI)root.getUI()).                                       getTitlePane();                if (titlePane != null) {                    tpd = titlePane.getPreferredSize();                    if (tpd != null) {                        tpWidth = tpd.width;                        tpHeight = tpd.height;                    }                }            }             return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) + i.left + i.right,                                 cpHeight + mbHeight + tpWidth + i.top + i.bottom);        }         /**         * Returns the minimum amount of space the layout needs.         *         * @param the Container for which this layout manager is being used         * @return a Dimension object containing the layout's minimum size         */        public Dimension minimumLayoutSize(Container parent) {            Dimension cpd, mbd, tpd;            int cpWidth = 0;            int cpHeight = 0;            int mbWidth = 0;            int mbHeight = 0;

Lines 1–500 of 989.