0N/A/*
2362N/A * Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/Apackage javax.swing.plaf.metal;
0N/A
0N/Aimport java.awt.event.*;
0N/Aimport java.beans.PropertyChangeEvent;
0N/Aimport java.beans.PropertyChangeListener;
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.border.*;
0N/Aimport javax.swing.event.*;
0N/Aimport javax.swing.plaf.*;
0N/Aimport javax.swing.plaf.basic.*;
0N/Aimport java.awt.*;
0N/Aimport java.io.*;
0N/Aimport java.security.*;
0N/A
0N/A/**
0N/A * Provides the metal look and feel implementation of <code>RootPaneUI</code>.
0N/A * <p>
0N/A * <code>MetalRootPaneUI</code> provides support for the
0N/A * <code>windowDecorationStyle</code> property of <code>JRootPane</code>.
0N/A * <code>MetalRootPaneUI</code> does this by way of installing a custom
0N/A * <code>LayoutManager</code>, a private <code>Component</code> to render
0N/A * the appropriate widgets, and a private <code>Border</code>. The
0N/A * <code>LayoutManager</code> is always installed, regardless of the value of
0N/A * the <code>windowDecorationStyle</code> property, but the
0N/A * <code>Border</code> and <code>Component</code> are only installed/added if
0N/A * the <code>windowDecorationStyle</code> is other than
0N/A * <code>JRootPane.NONE</code>.
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A *
0N/A * @author Terry Kellerman
0N/A * @since 1.4
0N/A */
0N/Apublic class MetalRootPaneUI extends BasicRootPaneUI
0N/A{
0N/A /**
0N/A * Keys to lookup borders in defaults table.
0N/A */
0N/A private static final String[] borderKeys = new String[] {
0N/A null, "RootPane.frameBorder", "RootPane.plainDialogBorder",
0N/A "RootPane.informationDialogBorder",
0N/A "RootPane.errorDialogBorder", "RootPane.colorChooserDialogBorder",
0N/A "RootPane.fileChooserDialogBorder", "RootPane.questionDialogBorder",
0N/A "RootPane.warningDialogBorder"
0N/A };
0N/A /**
0N/A * The amount of space (in pixels) that the cursor is changed on.
0N/A */
0N/A private static final int CORNER_DRAG_WIDTH = 16;
0N/A
0N/A /**
0N/A * Region from edges that dragging is active from.
0N/A */
0N/A private static final int BORDER_DRAG_THICKNESS = 5;
0N/A
0N/A /**
0N/A * Window the <code>JRootPane</code> is in.
0N/A */
0N/A private Window window;
0N/A
0N/A /**
0N/A * <code>JComponent</code> providing window decorations. This will be
0N/A * null if not providing window decorations.
0N/A */
0N/A private JComponent titlePane;
0N/A
0N/A /**
0N/A * <code>MouseInputListener</code> that is added to the parent
0N/A * <code>Window</code> the <code>JRootPane</code> is contained in.
0N/A */
0N/A private MouseInputListener mouseInputListener;
0N/A
0N/A /**
0N/A * The <code>LayoutManager</code> that is set on the
0N/A * <code>JRootPane</code>.
0N/A */
0N/A private LayoutManager layoutManager;
0N/A
0N/A /**
0N/A * <code>LayoutManager</code> of the <code>JRootPane</code> before we
0N/A * replaced it.
0N/A */
0N/A private LayoutManager savedOldLayout;
0N/A
0N/A /**
0N/A * <code>JRootPane</code> providing the look and feel for.
0N/A */
0N/A private JRootPane root;
0N/A
0N/A /**
0N/A * <code>Cursor</code> used to track the cursor set by the user.
0N/A * This is initially <code>Cursor.DEFAULT_CURSOR</code>.
0N/A */
0N/A private Cursor lastCursor =
0N/A Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);
0N/A
0N/A /**
0N/A * Creates a UI for a <code>JRootPane</code>.
0N/A *
0N/A * @param c the JRootPane the RootPaneUI will be created for
0N/A * @return the RootPaneUI implementation for the passed in JRootPane
0N/A */
0N/A public static ComponentUI createUI(JComponent c) {
0N/A return new MetalRootPaneUI();
0N/A }
0N/A
0N/A /**
0N/A * Invokes supers implementation of <code>installUI</code> to install
0N/A * the necessary state onto the passed in <code>JRootPane</code>
0N/A * to render the metal look and feel implementation of
0N/A * <code>RootPaneUI</code>. If
0N/A * the <code>windowDecorationStyle</code> property of the
0N/A * <code>JRootPane</code> is other than <code>JRootPane.NONE</code>,
0N/A * this will add a custom <code>Component</code> to render the widgets to
0N/A * <code>JRootPane</code>, as well as installing a custom
0N/A * <code>Border</code> and <code>LayoutManager</code> on the
0N/A * <code>JRootPane</code>.
0N/A *
0N/A * @param c the JRootPane to install state onto
0N/A */
0N/A public void installUI(JComponent c) {
0N/A super.installUI(c);
0N/A root = (JRootPane)c;
0N/A int style = root.getWindowDecorationStyle();
0N/A if (style != JRootPane.NONE) {
0N/A installClientDecorations(root);
0N/A }
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Invokes supers implementation to uninstall any of its state. This will
0N/A * also reset the <code>LayoutManager</code> of the <code>JRootPane</code>.
0N/A * If a <code>Component</code> has been added to the <code>JRootPane</code>
0N/A * to render the window decoration style, this method will remove it.
0N/A * Similarly, this will revert the Border and LayoutManager of the
0N/A * <code>JRootPane</code> to what it was before <code>installUI</code>
0N/A * was invoked.
0N/A *
0N/A * @param c the JRootPane to uninstall state from
0N/A */
0N/A public void uninstallUI(JComponent c) {
0N/A super.uninstallUI(c);
0N/A uninstallClientDecorations(root);
0N/A
0N/A layoutManager = null;
0N/A mouseInputListener = null;
0N/A root = null;
0N/A }
0N/A
0N/A /**
0N/A * Installs the appropriate <code>Border</code> onto the
0N/A * <code>JRootPane</code>.
0N/A */
0N/A void installBorder(JRootPane root) {
0N/A int style = root.getWindowDecorationStyle();
0N/A
0N/A if (style == JRootPane.NONE) {
0N/A LookAndFeel.uninstallBorder(root);
0N/A }
0N/A else {
0N/A LookAndFeel.installBorder(root, borderKeys[style]);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Removes any border that may have been installed.
0N/A */
0N/A private void uninstallBorder(JRootPane root) {
0N/A LookAndFeel.uninstallBorder(root);
0N/A }
0N/A
0N/A /**
0N/A * Installs the necessary Listeners on the parent <code>Window</code>,
0N/A * if there is one.
0N/A * <p>
0N/A * This takes the parent so that cleanup can be done from
0N/A * <code>removeNotify</code>, at which point the parent hasn't been
0N/A * reset yet.
0N/A *
0N/A * @param parent The parent of the JRootPane
0N/A */
0N/A private void installWindowListeners(JRootPane root, Component parent) {
0N/A if (parent instanceof Window) {
0N/A window = (Window)parent;
0N/A }
0N/A else {
0N/A window = SwingUtilities.getWindowAncestor(parent);
0N/A }
0N/A if (window != null) {
0N/A if (mouseInputListener == null) {
0N/A mouseInputListener = createWindowMouseInputListener(root);
0N/A }
0N/A window.addMouseListener(mouseInputListener);
0N/A window.addMouseMotionListener(mouseInputListener);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Uninstalls the necessary Listeners on the <code>Window</code> the
0N/A * Listeners were last installed on.
0N/A */
0N/A private void uninstallWindowListeners(JRootPane root) {
0N/A if (window != null) {
0N/A window.removeMouseListener(mouseInputListener);
0N/A window.removeMouseMotionListener(mouseInputListener);
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Installs the appropriate LayoutManager on the <code>JRootPane</code>
0N/A * to render the window decorations.
0N/A */
0N/A private void installLayout(JRootPane root) {
0N/A if (layoutManager == null) {
0N/A layoutManager = createLayoutManager();
0N/A }
0N/A savedOldLayout = root.getLayout();
0N/A root.setLayout(layoutManager);
0N/A }
0N/A
0N/A /**
0N/A * Uninstalls the previously installed <code>LayoutManager</code>.
0N/A */
0N/A private void uninstallLayout(JRootPane root) {
0N/A if (savedOldLayout != null) {
0N/A root.setLayout(savedOldLayout);
0N/A savedOldLayout = null;
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Installs the necessary state onto the JRootPane to render client
0N/A * decorations. This is ONLY invoked if the <code>JRootPane</code>
0N/A * has a decoration style other than <code>JRootPane.NONE</code>.
0N/A */
0N/A private void installClientDecorations(JRootPane root) {
0N/A installBorder(root);
0N/A
0N/A JComponent titlePane = createTitlePane(root);
0N/A
0N/A setTitlePane(root, titlePane);
0N/A installWindowListeners(root, root.getParent());
0N/A installLayout(root);
0N/A if (window != null) {
0N/A root.revalidate();
0N/A root.repaint();
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Uninstalls any state that <code>installClientDecorations</code> has
0N/A * installed.
0N/A * <p>
0N/A * NOTE: This may be called if you haven't installed client decorations
0N/A * yet (ie before <code>installClientDecorations</code> has been invoked).
0N/A */
0N/A private void uninstallClientDecorations(JRootPane root) {
0N/A uninstallBorder(root);
0N/A uninstallWindowListeners(root);
0N/A setTitlePane(root, null);
0N/A uninstallLayout(root);
0N/A // We have to revalidate/repaint root if the style is JRootPane.NONE
0N/A // only. When we needs to call revalidate/repaint with other styles
0N/A // the installClientDecorations is always called after this method
0N/A // imediatly and it will cause the revalidate/repaint at the proper
0N/A // time.
0N/A int style = root.getWindowDecorationStyle();
0N/A if (style == JRootPane.NONE) {
0N/A root.repaint();
0N/A root.revalidate();
0N/A }
0N/A // Reset the cursor, as we may have changed it to a resize cursor
0N/A if (window != null) {
0N/A window.setCursor(Cursor.getPredefinedCursor
0N/A (Cursor.DEFAULT_CURSOR));
0N/A }
0N/A window = null;
0N/A }
0N/A
0N/A /**
0N/A * Returns the <code>JComponent</code> to render the window decoration
0N/A * style.
0N/A */
0N/A private JComponent createTitlePane(JRootPane root) {
0N/A return new MetalTitlePane(root, this);
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>MouseListener</code> that will be added to the
0N/A * <code>Window</code> containing the <code>JRootPane</code>.
0N/A */
0N/A private MouseInputListener createWindowMouseInputListener(JRootPane root) {
0N/A return new MouseInputHandler();
0N/A }
0N/A
0N/A /**
0N/A * Returns a <code>LayoutManager</code> that will be set on the
0N/A * <code>JRootPane</code>.
0N/A */
0N/A private LayoutManager createLayoutManager() {
0N/A return new MetalRootLayout();
0N/A }
0N/A
0N/A /**
0N/A * Sets the window title pane -- the JComponent used to provide a plaf a
0N/A * way to override the native operating system's window title pane with
0N/A * one whose look and feel are controlled by the plaf. The plaf creates
0N/A * and sets this value; the default is null, implying a native operating
0N/A * system window title pane.
0N/A *
0N/A * @param content the <code>JComponent</code> to use for the window title pane.
0N/A */
0N/A private void setTitlePane(JRootPane root, JComponent titlePane) {
0N/A JLayeredPane layeredPane = root.getLayeredPane();
0N/A JComponent oldTitlePane = getTitlePane();
0N/A
0N/A if (oldTitlePane != null) {
0N/A oldTitlePane.setVisible(false);
0N/A layeredPane.remove(oldTitlePane);
0N/A }
0N/A if (titlePane != null) {
0N/A layeredPane.add(titlePane, JLayeredPane.FRAME_CONTENT_LAYER);
0N/A titlePane.setVisible(true);
0N/A }
0N/A this.titlePane = titlePane;
0N/A }
0N/A
0N/A /**
0N/A * Returns the <code>JComponent</code> rendering the title pane. If this
0N/A * returns null, it implies there is no need to render window decorations.
0N/A *
0N/A * @return the current window title pane, or null
0N/A * @see #setTitlePane
0N/A */
0N/A private JComponent getTitlePane() {
0N/A return titlePane;
0N/A }
0N/A
0N/A /**
0N/A * Returns the <code>JRootPane</code> we're providing the look and
0N/A * feel for.
0N/A */
0N/A private JRootPane getRootPane() {
0N/A return root;
0N/A }
0N/A
0N/A /**
0N/A * Invoked when a property changes. <code>MetalRootPaneUI</code> is
0N/A * primarily interested in events originating from the
0N/A * <code>JRootPane</code> it has been installed on identifying the
0N/A * property <code>windowDecorationStyle</code>. If the
0N/A * <code>windowDecorationStyle</code> has changed to a value other
0N/A * than <code>JRootPane.NONE</code>, this will add a <code>Component</code>
0N/A * to the <code>JRootPane</code> to render the window decorations, as well
0N/A * as installing a <code>Border</code> on the <code>JRootPane</code>.
0N/A * On the other hand, if the <code>windowDecorationStyle</code> has
0N/A * changed to <code>JRootPane.NONE</code>, this will remove the
0N/A * <code>Component</code> that has been added to the <code>JRootPane</code>
0N/A * as well resetting the Border to what it was before
0N/A * <code>installUI</code> was invoked.
0N/A *
0N/A * @param e A PropertyChangeEvent object describing the event source
0N/A * and the property that has changed.
0N/A */
0N/A public void propertyChange(PropertyChangeEvent e) {
0N/A super.propertyChange(e);
0N/A
0N/A String propertyName = e.getPropertyName();
0N/A if(propertyName == null) {
0N/A return;
0N/A }
0N/A
0N/A if(propertyName.equals("windowDecorationStyle")) {
0N/A JRootPane root = (JRootPane) e.getSource();
0N/A int style = root.getWindowDecorationStyle();
0N/A
0N/A // This is potentially more than needs to be done,
0N/A // but it rarely happens and makes the install/uninstall process
0N/A // simpler. MetalTitlePane also assumes it will be recreated if
0N/A // the decoration style changes.
0N/A uninstallClientDecorations(root);
0N/A if (style != JRootPane.NONE) {
0N/A installClientDecorations(root);
0N/A }
0N/A }
0N/A else if (propertyName.equals("ancestor")) {
0N/A uninstallWindowListeners(root);
0N/A if (((JRootPane)e.getSource()).getWindowDecorationStyle() !=
0N/A JRootPane.NONE) {
0N/A installWindowListeners(root, root.getParent());
0N/A }
0N/A }
0N/A return;
0N/A }
0N/A
0N/A /**
0N/A * A custom layout manager that is responsible for the layout of
0N/A * layeredPane, glassPane, menuBar and titlePane, if one has been
0N/A * installed.
0N/A */
0N/A // NOTE: Ideally this would extends JRootPane.RootLayout, but that
0N/A // would force this to be non-static.
0N/A private static class MetalRootLayout implements LayoutManager2 {
0N/A /**
0N/A * Returns the amount of space the layout would like to have.
0N/A *
0N/A * @param the Container for which this layout manager is being used
0N/A * @return a Dimension object containing the layout's preferred size
0N/A */
0N/A public Dimension preferredLayoutSize(Container parent) {
0N/A Dimension cpd, mbd, tpd;
0N/A int cpWidth = 0;
0N/A int cpHeight = 0;
0N/A int mbWidth = 0;
0N/A int mbHeight = 0;
0N/A int tpWidth = 0;
0N/A int tpHeight = 0;
0N/A Insets i = parent.getInsets();
0N/A JRootPane root = (JRootPane) parent;
0N/A
0N/A if(root.getContentPane() != null) {
0N/A cpd = root.getContentPane().getPreferredSize();
0N/A } else {
0N/A cpd = root.getSize();
0N/A }
0N/A if (cpd != null) {
0N/A cpWidth = cpd.width;
0N/A cpHeight = cpd.height;
0N/A }
0N/A
0N/A if(root.getMenuBar() != null) {
0N/A mbd = root.getMenuBar().getPreferredSize();
0N/A if (mbd != null) {
0N/A mbWidth = mbd.width;
0N/A mbHeight = mbd.height;
0N/A }
0N/A }
0N/A
0N/A if (root.getWindowDecorationStyle() != JRootPane.NONE &&
0N/A (root.getUI() instanceof MetalRootPaneUI)) {
0N/A JComponent titlePane = ((MetalRootPaneUI)root.getUI()).
0N/A getTitlePane();
0N/A if (titlePane != null) {
0N/A tpd = titlePane.getPreferredSize();
0N/A if (tpd != null) {
0N/A tpWidth = tpd.width;
0N/A tpHeight = tpd.height;
0N/A }
0N/A }
0N/A }
0N/A
0N/A return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) + i.left + i.right,
0N/A cpHeight + mbHeight + tpWidth + i.top + i.bottom);
0N/A }
0N/A
0N/A /**
0N/A * Returns the minimum amount of space the layout needs.
0N/A *
0N/A * @param the Container for which this layout manager is being used
0N/A * @return a Dimension object containing the layout's minimum size
0N/A */
0N/A public Dimension minimumLayoutSize(Container parent) {
0N/A Dimension cpd, mbd, tpd;
0N/A int cpWidth = 0;
0N/A int cpHeight = 0;
0N/A int mbWidth = 0;
0N/A int mbHeight = 0;
0N/A int tpWidth = 0;
0N/A int tpHeight = 0;
0N/A Insets i = parent.getInsets();
0N/A JRootPane root = (JRootPane) parent;
0N/A
0N/A if(root.getContentPane() != null) {
0N/A cpd = root.getContentPane().getMinimumSize();
0N/A } else {
0N/A cpd = root.getSize();
0N/A }
0N/A if (cpd != null) {
0N/A cpWidth = cpd.width;
0N/A cpHeight = cpd.height;
0N/A }
0N/A
0N/A if(root.getMenuBar() != null) {
0N/A mbd = root.getMenuBar().getMinimumSize();
0N/A if (mbd != null) {
0N/A mbWidth = mbd.width;
0N/A mbHeight = mbd.height;
0N/A }
0N/A }
0N/A if (root.getWindowDecorationStyle() != JRootPane.NONE &&
0N/A (root.getUI() instanceof MetalRootPaneUI)) {
0N/A JComponent titlePane = ((MetalRootPaneUI)root.getUI()).
0N/A getTitlePane();
0N/A if (titlePane != null) {
0N/A tpd = titlePane.getMinimumSize();
0N/A if (tpd != null) {
0N/A tpWidth = tpd.width;
0N/A tpHeight = tpd.height;
0N/A }
0N/A }
0N/A }
0N/A
0N/A return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) + i.left + i.right,
0N/A cpHeight + mbHeight + tpWidth + i.top + i.bottom);
0N/A }
0N/A
0N/A /**
0N/A * Returns the maximum amount of space the layout can use.
0N/A *
0N/A * @param the Container for which this layout manager is being used
0N/A * @return a Dimension object containing the layout's maximum size
0N/A */
0N/A public Dimension maximumLayoutSize(Container target) {
0N/A Dimension cpd, mbd, tpd;
0N/A int cpWidth = Integer.MAX_VALUE;
0N/A int cpHeight = Integer.MAX_VALUE;
0N/A int mbWidth = Integer.MAX_VALUE;
0N/A int mbHeight = Integer.MAX_VALUE;
0N/A int tpWidth = Integer.MAX_VALUE;
0N/A int tpHeight = Integer.MAX_VALUE;
0N/A Insets i = target.getInsets();
0N/A JRootPane root = (JRootPane) target;
0N/A
0N/A if(root.getContentPane() != null) {
0N/A cpd = root.getContentPane().getMaximumSize();
0N/A if (cpd != null) {
0N/A cpWidth = cpd.width;
0N/A cpHeight = cpd.height;
0N/A }
0N/A }
0N/A
0N/A if(root.getMenuBar() != null) {
0N/A mbd = root.getMenuBar().getMaximumSize();
0N/A if (mbd != null) {
0N/A mbWidth = mbd.width;
0N/A mbHeight = mbd.height;
0N/A }
0N/A }
0N/A
0N/A if (root.getWindowDecorationStyle() != JRootPane.NONE &&
0N/A (root.getUI() instanceof MetalRootPaneUI)) {
0N/A JComponent titlePane = ((MetalRootPaneUI)root.getUI()).
0N/A getTitlePane();
0N/A if (titlePane != null)
0N/A {
0N/A tpd = titlePane.getMaximumSize();
0N/A if (tpd != null) {
0N/A tpWidth = tpd.width;
0N/A tpHeight = tpd.height;
0N/A }
0N/A }
0N/A }
0N/A
0N/A int maxHeight = Math.max(Math.max(cpHeight, mbHeight), tpHeight);
0N/A // Only overflows if 3 real non-MAX_VALUE heights, sum to > MAX_VALUE
0N/A // Only will happen if sums to more than 2 billion units. Not likely.
0N/A if (maxHeight != Integer.MAX_VALUE) {
0N/A maxHeight = cpHeight + mbHeight + tpHeight + i.top + i.bottom;
0N/A }
0N/A
0N/A int maxWidth = Math.max(Math.max(cpWidth, mbWidth), tpWidth);
0N/A // Similar overflow comment as above
0N/A if (maxWidth != Integer.MAX_VALUE) {
0N/A maxWidth += i.left + i.right;
0N/A }
0N/A
0N/A return new Dimension(maxWidth, maxHeight);
0N/A }
0N/A
0N/A /**
0N/A * Instructs the layout manager to perform the layout for the specified
0N/A * container.
0N/A *
0N/A * @param the Container for which this layout manager is being used
0N/A */
0N/A public void layoutContainer(Container parent) {
0N/A JRootPane root = (JRootPane) parent;
0N/A Rectangle b = root.getBounds();
0N/A Insets i = root.getInsets();
0N/A int nextY = 0;
0N/A int w = b.width - i.right - i.left;
0N/A int h = b.height - i.top - i.bottom;
0N/A
0N/A if(root.getLayeredPane() != null) {
0N/A root.getLayeredPane().setBounds(i.left, i.top, w, h);
0N/A }
0N/A if(root.getGlassPane() != null) {
0N/A root.getGlassPane().setBounds(i.left, i.top, w, h);
0N/A }
0N/A // Note: This is laying out the children in the layeredPane,
0N/A // technically, these are not our children.
0N/A if (root.getWindowDecorationStyle() != JRootPane.NONE &&
0N/A (root.getUI() instanceof MetalRootPaneUI)) {
0N/A JComponent titlePane = ((MetalRootPaneUI)root.getUI()).
0N/A getTitlePane();
0N/A if (titlePane != null) {
0N/A Dimension tpd = titlePane.getPreferredSize();
0N/A if (tpd != null) {
0N/A int tpHeight = tpd.height;
0N/A titlePane.setBounds(0, 0, w, tpHeight);
0N/A nextY += tpHeight;
0N/A }
0N/A }
0N/A }
0N/A if(root.getMenuBar() != null) {
0N/A Dimension mbd = root.getMenuBar().getPreferredSize();
0N/A root.getMenuBar().setBounds(0, nextY, w, mbd.height);
0N/A nextY += mbd.height;
0N/A }
0N/A if(root.getContentPane() != null) {
0N/A Dimension cpd = root.getContentPane().getPreferredSize();
0N/A root.getContentPane().setBounds(0, nextY, w,
0N/A h < nextY ? 0 : h - nextY);
0N/A }
0N/A }
0N/A
0N/A public void addLayoutComponent(String name, Component comp) {}
0N/A public void removeLayoutComponent(Component comp) {}
0N/A public void addLayoutComponent(Component comp, Object constraints) {}
0N/A public float getLayoutAlignmentX(Container target) { return 0.0f; }
0N/A public float getLayoutAlignmentY(Container target) { return 0.0f; }
0N/A public void invalidateLayout(Container target) {}
0N/A }
0N/A
0N/A
0N/A /**
0N/A * Maps from positions to cursor type. Refer to calculateCorner and
0N/A * calculatePosition for details of this.
0N/A */
0N/A private static final int[] cursorMapping = new int[]
0N/A { Cursor.NW_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, Cursor.N_RESIZE_CURSOR,
0N/A Cursor.NE_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR,
0N/A Cursor.NW_RESIZE_CURSOR, 0, 0, 0, Cursor.NE_RESIZE_CURSOR,
0N/A Cursor.W_RESIZE_CURSOR, 0, 0, 0, Cursor.E_RESIZE_CURSOR,
0N/A Cursor.SW_RESIZE_CURSOR, 0, 0, 0, Cursor.SE_RESIZE_CURSOR,
0N/A Cursor.SW_RESIZE_CURSOR, Cursor.SW_RESIZE_CURSOR, Cursor.S_RESIZE_CURSOR,
0N/A Cursor.SE_RESIZE_CURSOR, Cursor.SE_RESIZE_CURSOR
0N/A };
0N/A
0N/A /**
0N/A * MouseInputHandler is responsible for handling resize/moving of
0N/A * the Window. It sets the cursor directly on the Window when then
0N/A * mouse moves over a hot spot.
0N/A */
0N/A private class MouseInputHandler implements MouseInputListener {
0N/A /**
0N/A * Set to true if the drag operation is moving the window.
0N/A */
0N/A private boolean isMovingWindow;
0N/A
0N/A /**
0N/A * Used to determine the corner the resize is occuring from.
0N/A */
0N/A private int dragCursor;
0N/A
0N/A /**
0N/A * X location the mouse went down on for a drag operation.
0N/A */
0N/A private int dragOffsetX;
0N/A
0N/A /**
0N/A * Y location the mouse went down on for a drag operation.
0N/A */
0N/A private int dragOffsetY;
0N/A
0N/A /**
0N/A * Width of the window when the drag started.
0N/A */
0N/A private int dragWidth;
0N/A
0N/A /**
0N/A * Height of the window when the drag started.
0N/A */
0N/A private int dragHeight;
0N/A
0N/A public void mousePressed(MouseEvent ev) {
0N/A JRootPane rootPane = getRootPane();
0N/A
0N/A if (rootPane.getWindowDecorationStyle() == JRootPane.NONE) {
0N/A return;
0N/A }
0N/A Point dragWindowOffset = ev.getPoint();
0N/A Window w = (Window)ev.getSource();
0N/A if (w != null) {
0N/A w.toFront();
0N/A }
0N/A Point convertedDragWindowOffset = SwingUtilities.convertPoint(
0N/A w, dragWindowOffset, getTitlePane());
0N/A
0N/A Frame f = null;
0N/A Dialog d = null;
0N/A
0N/A if (w instanceof Frame) {
0N/A f = (Frame)w;
0N/A } else if (w instanceof Dialog) {
0N/A d = (Dialog)w;
0N/A }
0N/A
0N/A int frameState = (f != null) ? f.getExtendedState() : 0;
0N/A
0N/A if (getTitlePane() != null &&
0N/A getTitlePane().contains(convertedDragWindowOffset)) {
0N/A if ((f != null && ((frameState & Frame.MAXIMIZED_BOTH) == 0)
0N/A || (d != null))
0N/A && dragWindowOffset.y >= BORDER_DRAG_THICKNESS
0N/A && dragWindowOffset.x >= BORDER_DRAG_THICKNESS
0N/A && dragWindowOffset.x < w.getWidth()
0N/A - BORDER_DRAG_THICKNESS) {
0N/A isMovingWindow = true;
0N/A dragOffsetX = dragWindowOffset.x;
0N/A dragOffsetY = dragWindowOffset.y;
0N/A }
0N/A }
0N/A else if (f != null && f.isResizable()
0N/A && ((frameState & Frame.MAXIMIZED_BOTH) == 0)
0N/A || (d != null && d.isResizable())) {
0N/A dragOffsetX = dragWindowOffset.x;
0N/A dragOffsetY = dragWindowOffset.y;
0N/A dragWidth = w.getWidth();
0N/A dragHeight = w.getHeight();
0N/A dragCursor = getCursor(calculateCorner(
0N/A w, dragWindowOffset.x, dragWindowOffset.y));
0N/A }
0N/A }
0N/A
0N/A public void mouseReleased(MouseEvent ev) {
0N/A if (dragCursor != 0 && window != null && !window.isValid()) {
0N/A // Some Window systems validate as you resize, others won't,
0N/A // thus the check for validity before repainting.
0N/A window.validate();
0N/A getRootPane().repaint();
0N/A }
0N/A isMovingWindow = false;
0N/A dragCursor = 0;
0N/A }
0N/A
0N/A public void mouseMoved(MouseEvent ev) {
0N/A JRootPane root = getRootPane();
0N/A
0N/A if (root.getWindowDecorationStyle() == JRootPane.NONE) {
0N/A return;
0N/A }
0N/A
0N/A Window w = (Window)ev.getSource();
0N/A
0N/A Frame f = null;
0N/A Dialog d = null;
0N/A
0N/A if (w instanceof Frame) {
0N/A f = (Frame)w;
0N/A } else if (w instanceof Dialog) {
0N/A d = (Dialog)w;
0N/A }
0N/A
0N/A // Update the cursor
0N/A int cursor = getCursor(calculateCorner(w, ev.getX(), ev.getY()));
0N/A
0N/A if (cursor != 0 && ((f != null && (f.isResizable() &&
0N/A (f.getExtendedState() & Frame.MAXIMIZED_BOTH) == 0))
0N/A || (d != null && d.isResizable()))) {
0N/A w.setCursor(Cursor.getPredefinedCursor(cursor));
0N/A }
0N/A else {
0N/A w.setCursor(lastCursor);
0N/A }
0N/A }
0N/A
0N/A private void adjust(Rectangle bounds, Dimension min, int deltaX,
0N/A int deltaY, int deltaWidth, int deltaHeight) {
0N/A bounds.x += deltaX;
0N/A bounds.y += deltaY;
0N/A bounds.width += deltaWidth;
0N/A bounds.height += deltaHeight;
0N/A if (min != null) {
0N/A if (bounds.width < min.width) {
0N/A int correction = min.width - bounds.width;
0N/A if (deltaX != 0) {
0N/A bounds.x -= correction;
0N/A }
0N/A bounds.width = min.width;
0N/A }
0N/A if (bounds.height < min.height) {
0N/A int correction = min.height - bounds.height;
0N/A if (deltaY != 0) {
0N/A bounds.y -= correction;
0N/A }
0N/A bounds.height = min.height;
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void mouseDragged(MouseEvent ev) {
0N/A Window w = (Window)ev.getSource();
0N/A Point pt = ev.getPoint();
0N/A
0N/A if (isMovingWindow) {
0N/A Point eventLocationOnScreen = ev.getLocationOnScreen();
0N/A w.setLocation(eventLocationOnScreen.x - dragOffsetX,
0N/A eventLocationOnScreen.y - dragOffsetY);
0N/A }
0N/A else if (dragCursor != 0) {
0N/A Rectangle r = w.getBounds();
0N/A Rectangle startBounds = new Rectangle(r);
0N/A Dimension min = w.getMinimumSize();
0N/A
0N/A switch (dragCursor) {
0N/A case Cursor.E_RESIZE_CURSOR:
0N/A adjust(r, min, 0, 0, pt.x + (dragWidth - dragOffsetX) -
0N/A r.width, 0);
0N/A break;
0N/A case Cursor.S_RESIZE_CURSOR:
0N/A adjust(r, min, 0, 0, 0, pt.y + (dragHeight - dragOffsetY) -
0N/A r.height);
0N/A break;
0N/A case Cursor.N_RESIZE_CURSOR:
0N/A adjust(r, min, 0, pt.y -dragOffsetY, 0,
0N/A -(pt.y - dragOffsetY));
0N/A break;
0N/A case Cursor.W_RESIZE_CURSOR:
0N/A adjust(r, min, pt.x - dragOffsetX, 0,
0N/A -(pt.x - dragOffsetX), 0);
0N/A break;
0N/A case Cursor.NE_RESIZE_CURSOR:
0N/A adjust(r, min, 0, pt.y - dragOffsetY,
0N/A pt.x + (dragWidth - dragOffsetX) - r.width,
0N/A -(pt.y - dragOffsetY));
0N/A break;
0N/A case Cursor.SE_RESIZE_CURSOR:
0N/A adjust(r, min, 0, 0,
0N/A pt.x + (dragWidth - dragOffsetX) - r.width,
0N/A pt.y + (dragHeight - dragOffsetY) -
0N/A r.height);
0N/A break;
0N/A case Cursor.NW_RESIZE_CURSOR:
0N/A adjust(r, min, pt.x - dragOffsetX,
0N/A pt.y - dragOffsetY,
0N/A -(pt.x - dragOffsetX),
0N/A -(pt.y - dragOffsetY));
0N/A break;
0N/A case Cursor.SW_RESIZE_CURSOR:
0N/A adjust(r, min, pt.x - dragOffsetX, 0,
0N/A -(pt.x - dragOffsetX),
0N/A pt.y + (dragHeight - dragOffsetY) - r.height);
0N/A break;
0N/A default:
0N/A break;
0N/A }
0N/A if (!r.equals(startBounds)) {
0N/A w.setBounds(r);
0N/A // Defer repaint/validate on mouseReleased unless dynamic
0N/A // layout is active.
0N/A if (Toolkit.getDefaultToolkit().isDynamicLayoutActive()) {
0N/A w.validate();
0N/A getRootPane().repaint();
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A public void mouseEntered(MouseEvent ev) {
0N/A Window w = (Window)ev.getSource();
0N/A lastCursor = w.getCursor();
0N/A mouseMoved(ev);
0N/A }
0N/A
0N/A public void mouseExited(MouseEvent ev) {
0N/A Window w = (Window)ev.getSource();
0N/A w.setCursor(lastCursor);
0N/A }
0N/A
0N/A public void mouseClicked(MouseEvent ev) {
0N/A Window w = (Window)ev.getSource();
0N/A Frame f = null;
0N/A
0N/A if (w instanceof Frame) {
0N/A f = (Frame)w;
0N/A } else {
0N/A return;
0N/A }
0N/A
0N/A Point convertedPoint = SwingUtilities.convertPoint(
0N/A w, ev.getPoint(), getTitlePane());
0N/A
0N/A int state = f.getExtendedState();
0N/A if (getTitlePane() != null &&
0N/A getTitlePane().contains(convertedPoint)) {
0N/A if ((ev.getClickCount() % 2) == 0 &&
0N/A ((ev.getModifiers() & InputEvent.BUTTON1_MASK) != 0)) {
0N/A if (f.isResizable()) {
0N/A if ((state & Frame.MAXIMIZED_BOTH) != 0) {
0N/A f.setExtendedState(state & ~Frame.MAXIMIZED_BOTH);
0N/A }
0N/A else {
0N/A f.setExtendedState(state | Frame.MAXIMIZED_BOTH);
0N/A }
0N/A return;
0N/A }
0N/A }
0N/A }
0N/A }
0N/A
0N/A /**
0N/A * Returns the corner that contains the point <code>x</code>,
0N/A * <code>y</code>, or -1 if the position doesn't match a corner.
0N/A */
0N/A private int calculateCorner(Window w, int x, int y) {
0N/A Insets insets = w.getInsets();
0N/A int xPosition = calculatePosition(x - insets.left,
0N/A w.getWidth() - insets.left - insets.right);
0N/A int yPosition = calculatePosition(y - insets.top,
0N/A w.getHeight() - insets.top - insets.bottom);
0N/A
0N/A if (xPosition == -1 || yPosition == -1) {
0N/A return -1;
0N/A }
0N/A return yPosition * 5 + xPosition;
0N/A }
0N/A
0N/A /**
0N/A * Returns the Cursor to render for the specified corner. This returns
0N/A * 0 if the corner doesn't map to a valid Cursor
0N/A */
0N/A private int getCursor(int corner) {
0N/A if (corner == -1) {
0N/A return 0;
0N/A }
0N/A return cursorMapping[corner];
0N/A }
0N/A
0N/A /**
0N/A * Returns an integer indicating the position of <code>spot</code>
0N/A * in <code>width</code>. The return value will be:
0N/A * 0 if < BORDER_DRAG_THICKNESS
0N/A * 1 if < CORNER_DRAG_WIDTH
0N/A * 2 if >= CORNER_DRAG_WIDTH && < width - BORDER_DRAG_THICKNESS
0N/A * 3 if >= width - CORNER_DRAG_WIDTH
0N/A * 4 if >= width - BORDER_DRAG_THICKNESS
0N/A * 5 otherwise
0N/A */
0N/A private int calculatePosition(int spot, int width) {
0N/A if (spot < BORDER_DRAG_THICKNESS) {
0N/A return 0;
0N/A }
0N/A if (spot < CORNER_DRAG_WIDTH) {
0N/A return 1;
0N/A }
0N/A if (spot >= (width - BORDER_DRAG_THICKNESS)) {
0N/A return 4;
0N/A }
0N/A if (spot >= (width - CORNER_DRAG_WIDTH)) {
0N/A return 3;
0N/A }
0N/A return 2;
0N/A }
0N/A }
0N/A}