All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pushingpixels.substance.internal.ui.SubstanceRootPaneUI Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2005-2010 Substance Kirill Grouchnikov. All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 * 
 *  o Redistributions of source code must retain the above copyright notice, 
 *    this list of conditions and the following disclaimer. 
 *     
 *  o Redistributions in binary form must reproduce the above copyright notice, 
 *    this list of conditions and the following disclaimer in the documentation 
 *    and/or other materials provided with the distribution. 
 *     
 *  o Neither the name of Substance Kirill Grouchnikov nor the names of 
 *    its contributors may be used to endorse or promote products derived 
 *    from this software without specific prior written permission. 
 *     
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 */
package org.pushingpixels.substance.internal.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.PointerInfo;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.HierarchyEvent;
import java.awt.event.HierarchyListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLayeredPane;
import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputAdapter;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ColorUIResource;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicRootPaneUI;

import com.sun.awt.AWTUtilities;
import org.pushingpixels.substance.api.SubstanceLookAndFeel;
import org.pushingpixels.substance.api.SubstanceSkin;
import org.pushingpixels.substance.internal.animation.RootPaneDefaultButtonTracker;
import org.pushingpixels.substance.internal.painter.BackgroundPaintingUtils;
import org.pushingpixels.substance.internal.utils.MemoryAnalyzer;
import org.pushingpixels.substance.internal.utils.SubstanceColorUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
import org.pushingpixels.substance.internal.utils.SubstanceTitlePane;

/**
 * UI for root panes in Substance  look and feel.
 * 
 * @author Kirill Grouchnikov
 * @author Larry Salibra (fix for defect 198)
 */
public class SubstanceRootPaneUI extends BasicRootPaneUI {
	private enum CursorState {
		EXITED, ENTERED, NIL
	}

	/**
	 * 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 JRootPane is in.
	 */
	private Window window;

	/**
	 * JComponent providing window decorations. This will be null
	 * if not providing window decorations.
	 */
	private JComponent titlePane;

	/**
	 * MouseInputListener that is added to the parent
	 * Window the JRootPane is contained in.
	 */
	private MouseInputListener substanceMouseInputListener;

	/**
	 * Mouse listener on the title pane (dragging).
	 */
	private MouseInputListener substanceTitleMouseInputListener;

	/**
	 * The LayoutManager that is set on the JRootPane.
	 */
	private LayoutManager layoutManager;

	/**
	 * LayoutManager of the JRootPane before we
	 * replaced it.
	 */
	private LayoutManager savedOldLayout;

	/**
	 * JRootPane providing the look and feel for.
	 */
	protected JRootPane root;

	/**
	 * Window listener that stops all Substance thread when the last frame is
	 * disposed.
	 */
	protected WindowListener substanceWindowListener;

	/**
	 * The current window.
	 */
	protected Window substanceCurrentWindow;

	/**
	 * Hierarchy listener to keep track of the associated top-level window.
	 */
	protected HierarchyListener substanceHierarchyListener;

	/**
	 * Component listener to keep track of the primary graphics configuration
	 * (for recomputing the maximized bounds) - fix for defect 213.
	 */
	protected ComponentListener substanceWindowComponentListener;

	/**
	 * The graphics configuration that contains the top-left corner of the
	 * window (fix for defect 213).
	 */
	protected GraphicsConfiguration currentRootPaneGC;

	protected PropertyChangeListener substancePropertyChangeListener;

	/**
	 * Cursor used to track the cursor set by the user. This is
	 * initially Cursor.DEFAULT_CURSOR.
	 */
	private Cursor lastCursor = Cursor
			.getPredefinedCursor(Cursor.DEFAULT_CURSOR);

	/**
	 * Optimization to speed up the
	 * {@link SubstanceCoreUtilities#getSkin(Component)} implementation.
	 */
	private static int rootPanesWithCustomSkin = 0;

	/**
	 * Creates a UI for a JRootPane.
	 * 
	 * @param comp
	 *            the JRootPane the RootPaneUI will be created for
	 * @return the RootPaneUI implementation for the passed in JRootPane
	 */
	public static ComponentUI createUI(JComponent comp) {
		SubstanceCoreUtilities.testComponentCreationThreadingViolation(comp);
		return new SubstanceRootPaneUI();
	}

	/**
	 * Invokes supers implementation of installUI to install the
	 * necessary state onto the passed in JRootPane to render the
	 * metal look and feel implementation of RootPaneUI. If the
	 * windowDecorationStyle property of the JRootPane
	 * is other than JRootPane.NONE, this will add a custom
	 * Component to render the widgets to JRootPane,
	 * as well as installing a custom Border and
	 * LayoutManager on the JRootPane.
	 * 
	 * @param c
	 *            the JRootPane to install state onto
	 */
	@Override
	public void installUI(JComponent c) {
		super.installUI(c);
        if (SubstanceCoreUtilities.isRoundedCorners(c)) {
            c.addHierarchyListener(RESIZE_LOADER);
        }
		this.root = (JRootPane) c;
		int style = this.root.getWindowDecorationStyle();
		if (style != JRootPane.NONE) {
			this.installClientDecorations(this.root);
		}

		if (SubstanceCoreUtilities.isRootPaneModified(this.root)) {
			propagateModificationState();
		}

		if (this.root.getClientProperty(SubstanceLookAndFeel.SKIN_PROPERTY) instanceof SubstanceSkin) {
			rootPanesWithCustomSkin++;
		}
	}

	/**
	 * Invokes supers implementation to uninstall any of its state. This will
	 * also reset the LayoutManager of the JRootPane.
	 * If a Component has been added to the JRootPane
	 * to render the window decoration style, this method will remove it.
	 * Similarly, this will revert the Border and LayoutManager of the
	 * JRootPane to what it was before installUI was
	 * invoked.
	 * 
	 * @param c
	 *            the JRootPane to uninstall state from
	 */
	@Override
	public void uninstallUI(JComponent c) {
		super.uninstallUI(c);
		this.uninstallClientDecorations(this.root);

		this.layoutManager = null;
		this.substanceMouseInputListener = null;

		if (this.root.getClientProperty(SubstanceLookAndFeel.SKIN_PROPERTY) instanceof SubstanceSkin) {
			rootPanesWithCustomSkin--;
		}

		this.root = null;
	}

	/**
	 * Installs the appropriate Border onto the
	 * JRootPane.
	 * 
	 * @param root
	 *            Root pane.
	 */
	public void installBorder(JRootPane root) {
		int style = root.getWindowDecorationStyle();

		if (style == JRootPane.NONE) {
			LookAndFeel.uninstallBorder(root);
		} else {
			LookAndFeel.installBorder(root, "RootPane.border");
		}
	}

	/**
	 * Removes any border that may have been installed.
	 * 
	 * @param root
	 *            Root pane.
	 */
	private void uninstallBorder(JRootPane root) {
		LookAndFeel.uninstallBorder(root);
	}

	@Override
	protected void installDefaults(JRootPane c) {
		super.installDefaults(c);
		// support for per-window skins
		Color backgr = c.getBackground();
		if ((backgr == null) || (backgr instanceof UIResource)) {
			Color backgroundFillColor = SubstanceColorUtilities
					.getBackgroundFillColor(c);
			// fix for issue 244 - set the root pane BG color
			if (backgroundFillColor != null) {
				c.setBackground(new ColorUIResource(backgroundFillColor));
			}
		}
	}

	@Override
	public void update(Graphics g, JComponent c) {
		if (!SubstanceLookAndFeel.isCurrentLookAndFeel())
			return;

		// fix for issue 244 - paint the entire root pane so that it
		// picks the correct watermark
		if (SubstanceCoreUtilities.isOpaque(c)) {
			BackgroundPaintingUtils.update(g, c, false);
		}
		super.paint(g, c);
	}

	/**
	 * Installs the necessary Listeners on the parent Window, if
	 * there is one.
	 * 

* This takes the parent so that cleanup can be done from * removeNotify, at which point the parent hasn't been reset * yet. * * * @param root * Root pane. * @param parent * The parent of the JRootPane */ private void installWindowListeners(JRootPane root, Component parent) { if (parent instanceof Window) { this.window = (Window) parent; } else { this.window = SwingUtilities.getWindowAncestor(parent); } // System.out.println(titlePanes.size() + " entries in map after adding // " // + window.getClass().getName() + ":" + window.hashCode()); // for (Iterator>> it = // titlePanes // .entrySet().iterator(); it.hasNext();) { // Map.Entry> entry = it // .next(); // Window w = entry.getValue().get(); // System.out.println("\t" + w.getClass().getName() // + ":" + w.hashCode()); // } if (this.window != null) { if (this.substanceMouseInputListener == null) { this.substanceMouseInputListener = this .createWindowMouseInputListener(root); } this.window.addMouseListener(this.substanceMouseInputListener); this.window .addMouseMotionListener(this.substanceMouseInputListener); if (this.titlePane != null) { if (this.substanceTitleMouseInputListener == null) { this.substanceTitleMouseInputListener = new TitleMouseInputHandler(); } this.titlePane .addMouseMotionListener(this.substanceTitleMouseInputListener); this.titlePane .addMouseListener(this.substanceTitleMouseInputListener); } this.setMaximized(); } } /** * Uninstalls the necessary Listeners on the Window the * Listeners were last installed on. * * @param root * Root pane. */ private void uninstallWindowListeners(JRootPane root) { if (this.window != null) { this.window.removeMouseListener(this.substanceMouseInputListener); this.window .removeMouseMotionListener(this.substanceMouseInputListener); } if (this.titlePane != null) { this.titlePane .removeMouseListener(this.substanceTitleMouseInputListener); this.titlePane .removeMouseMotionListener(this.substanceTitleMouseInputListener); } } /** * Installs the appropriate LayoutManager on the JRootPane to * render the window decorations. * * @param root * Root pane. */ private void installLayout(JRootPane root) { if (this.layoutManager == null) { this.layoutManager = this.createLayoutManager(); } this.savedOldLayout = root.getLayout(); root.setLayout(this.layoutManager); } @Override protected void installListeners(final JRootPane root) { super.installListeners(root); // System.out.println("Listeners on root " + root.hashCode()); this.substanceHierarchyListener = new HierarchyListener() { @Override public void hierarchyChanged(HierarchyEvent e) { Component parent = root.getParent(); if (parent == null) { // fix for defect 271 - check for null parent // as early as possible return; } // System.out.println("Root pane " + root.hashCode() // + " parent : " + parent.getClass().getName()); if (MemoryAnalyzer.isRunning()) { MemoryAnalyzer.enqueueUsage("Root pane @" + root.hashCode() + "\n" + SubstanceCoreUtilities.getHierarchy(parent)); } if (parent.getClass().getName().startsWith( "org.jdesktop.jdic.tray") || (parent.getClass().getName().compareTo( "javax.swing.Popup$HeavyWeightWindow") == 0)) { // Workaround for bug 240 - using JDIC system tray // menu results in an HierarchyEvent being fired right // after a MouseEvent. Somehow, the // EventQueue.getCurrentEvent() returns the HierarchyEvent // even when the MouseEvent is being processed, resulting // in zeroed modifiers set on the ActionEvent passed // to the action listeners on that menu item. SwingUtilities.invokeLater(new Runnable() { @Override public void run() { root .removeHierarchyListener(substanceHierarchyListener); // System.out.println(root.hashCode() + ":" // + root.getHierarchyListeners().length); substanceHierarchyListener = null; } }); } Window currWindow; if (parent instanceof Window) { currWindow = (Window) parent; } else { currWindow = SwingUtilities.getWindowAncestor(parent); } if (substanceWindowListener != null) { substanceCurrentWindow .removeWindowListener(substanceWindowListener); substanceWindowListener = null; } if (substanceWindowComponentListener != null) { substanceCurrentWindow .removeComponentListener(substanceWindowComponentListener); substanceWindowComponentListener = null; } if (currWindow != null) { // fix for bug 116 - stopping threads when all frames // are not displayable substanceWindowListener = new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { SubstanceCoreUtilities .testWindowCloseThreadingViolation(e .getWindow()); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { Frame[] frames = Frame.getFrames(); for (Frame frame : frames) { if (frame.isDisplayable()) return; } SubstanceCoreUtilities.stopThreads(); } }); } }; if (!(parent instanceof JInternalFrame)) { currWindow.addWindowListener(substanceWindowListener); } // fix for defect 213 - maximizing frame under multiple // screens shouldn't always use insets of the primary // screen. substanceWindowComponentListener = new ComponentAdapter() { @Override public void componentMoved(ComponentEvent e) { this.processNewPosition(); } @Override public void componentResized(ComponentEvent e) { this.processNewPosition(); } protected void processNewPosition() { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { if (window == null) return; if (!window.isShowing() || !window.isDisplayable()) { currentRootPaneGC = null; return; } GraphicsEnvironment ge = GraphicsEnvironment .getLocalGraphicsEnvironment(); GraphicsDevice[] gds = ge .getScreenDevices(); if (gds.length == 1) return; Point midLoc = new Point(window .getLocationOnScreen().x + window.getWidth() / 2, window .getLocationOnScreen().y + window.getHeight() / 2); // System.out.println("Loc : " // + window.getLocationOnScreen() // + ", width : " // + window.getWidth() // + ", mid : " + midLoc); int index = 0; for (GraphicsDevice gd : gds) { GraphicsConfiguration gc = gd .getDefaultConfiguration(); Rectangle bounds = gc.getBounds(); // System.out.println("Bounds : " // + bounds); if (bounds.contains(midLoc)) { if (gc != currentRootPaneGC) { currentRootPaneGC = gc; setMaximized(); // System.out.println("Set"); } break; } index++; } } }); } }; // fix for defect 225 - install the listener only on // JFrames. if (parent instanceof JFrame) { currWindow .addComponentListener(substanceWindowComponentListener); } SubstanceRootPaneUI.this.window = currWindow; } substanceCurrentWindow = currWindow; } }; root.addHierarchyListener(this.substanceHierarchyListener); // System.out.println(root.hashCode() + ":" // + root.getHierarchyListeners().length); JButton defaultButton = root.getDefaultButton(); if (defaultButton != null) { RootPaneDefaultButtonTracker.update(defaultButton); } this.substancePropertyChangeListener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("defaultButton".equals(evt.getPropertyName())) { JButton prev = (JButton) evt.getOldValue(); JButton next = (JButton) evt.getNewValue(); RootPaneDefaultButtonTracker.update(prev); RootPaneDefaultButtonTracker.update(next); } if (SubstanceLookAndFeel.WINDOW_MODIFIED.equals(evt .getPropertyName())) { propagateModificationState(); } } }; root.addPropertyChangeListener(this.substancePropertyChangeListener); } /* * (non-Javadoc) * * @see * javax.swing.plaf.basic.BasicRootPaneUI#uninstallListeners(javax.swing * .JRootPane) */ @Override protected void uninstallListeners(JRootPane root) { // fix for bug 116 - stopping threads when all frames are // not displayable if (this.window != null) { this.window.removeWindowListener(this.substanceWindowListener); this.substanceWindowListener = null; this.window .removeComponentListener(this.substanceWindowComponentListener); this.substanceWindowComponentListener = null; } root.removeHierarchyListener(this.substanceHierarchyListener); this.substanceHierarchyListener = null; root.removePropertyChangeListener(this.substancePropertyChangeListener); this.substancePropertyChangeListener = null; super.uninstallListeners(root); } /** * Uninstalls the previously installed LayoutManager. * * @param root * Root pane. */ private void uninstallLayout(JRootPane root) { if (this.savedOldLayout != null) { root.setLayout(this.savedOldLayout); this.savedOldLayout = null; } } /** * Installs the necessary state onto the JRootPane to render client * decorations. This is ONLY invoked if the JRootPane has a * decoration style other than JRootPane.NONE. * * @param root * Root pane. */ private void installClientDecorations(JRootPane root) { this.installBorder(root); JComponent titlePane = this.createTitlePane(root); this.setTitlePane(root, titlePane); this.installWindowListeners(root, root.getParent()); this.installLayout(root); if (this.window != null) { root.revalidate(); root.repaint(); } } /** * Uninstalls any state that installClientDecorations has * installed. *

* NOTE: This may be called if you haven't installed client decorations yet * (ie before installClientDecorations has been invoked). * * @param root * Root pane. */ private void uninstallClientDecorations(JRootPane root) { this.uninstallBorder(root); this.uninstallWindowListeners(root); this.setTitlePane(root, null); this.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 (this.window != null) { this.window.setCursor(Cursor .getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } this.window = null; } /** * Returns the JComponent to render the window decoration * style. * * @param root * Root pane. * @return The title pane component. */ protected JComponent createTitlePane(JRootPane root) { return new SubstanceTitlePane(root, this); } /** * Returns a MouseListener that will be added to the * Window containing the JRootPane. * * @param root * Root pane. * @return Window mouse listener. */ private MouseInputListener createWindowMouseInputListener(JRootPane root) { return new MouseInputHandler(); } /** * Returns a LayoutManager that will be set on the * JRootPane. * * @return Layout manager. */ protected LayoutManager createLayoutManager() { return new SubstanceRootLayout(); } /** * 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 root * Root pane * @param titlePane * The JComponent to use for the window title pane. */ private void setTitlePane(JRootPane root, JComponent titlePane) { JLayeredPane layeredPane = root.getLayeredPane(); JComponent oldTitlePane = this.getTitlePane(); if (oldTitlePane != null) { // fix for defect 109 - memory leak on skin change if (oldTitlePane instanceof SubstanceTitlePane) ((SubstanceTitlePane) oldTitlePane).uninstall(); // oldTitlePane.setVisible(false); layeredPane.remove(oldTitlePane); } if (titlePane != null) { layeredPane.add(titlePane, JLayeredPane.FRAME_CONTENT_LAYER); titlePane.setVisible(true); } this.titlePane = titlePane; } /** * Sets maximized bounds according to the display screen insets. */ public void setMaximized() { Component tla = this.root.getTopLevelAncestor(); // fix for defect 213 - maximizing frame under multiple // screens shouldn't always use insets of the primary // screen. GraphicsConfiguration gc = (currentRootPaneGC != null) ? currentRootPaneGC : tla.getGraphicsConfiguration(); Rectangle screenBounds = gc.getBounds(); screenBounds.x = 0; screenBounds.y = 0; Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc); Rectangle maxBounds = new Rectangle( (screenBounds.x + screenInsets.left), (screenBounds.y + screenInsets.top), screenBounds.width - ((screenInsets.left + screenInsets.right)), screenBounds.height - ((screenInsets.top + screenInsets.bottom))); if (tla instanceof JFrame) ((JFrame) tla).setMaximizedBounds(maxBounds); if (MemoryAnalyzer.isRunning()) { MemoryAnalyzer.enqueueUsage("Frame set to bounds " + maxBounds); } } /** * Returns the JComponent rendering the title pane. If this * returns null, it implies there is no need to render window decorations. * This method is for internal use only. * * @see #setTitlePane(javax.swing.JRootPane, javax.swing.JComponent) * @return Title pane. */ public JComponent getTitlePane() { return this.titlePane; } /** * Returns the JRootPane we're providing the look and feel for. * * @return The associated root pane. */ protected JRootPane getRootPane() { return this.root; } /* * (non-Javadoc) * * @seejavax.swing.plaf.basic.BasicRootPaneUI#propertyChange(java.beans. * PropertyChangeEvent) */ @Override 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.uninstallClientDecorations(root); if (style != JRootPane.NONE) { this.installClientDecorations(root); } } if (propertyName.equals("ancestor")) { this.uninstallWindowListeners(this.root); if (((JRootPane) e.getSource()).getWindowDecorationStyle() != JRootPane.NONE) { this.installWindowListeners(this.root, this.root.getParent()); } } if (propertyName.equals("background")) { SubstanceLookAndFeel.getTitlePaneComponent(window).setBackground( (Color) e.getNewValue()); } if (propertyName.equals(SubstanceLookAndFeel.SKIN_PROPERTY)) { SubstanceSkin oldValue = (SubstanceSkin) e.getOldValue(); SubstanceSkin newValue = (SubstanceSkin) e.getNewValue(); if ((oldValue == null) && (newValue != null)) { rootPanesWithCustomSkin++; } if ((oldValue != null) && (newValue == null)) { rootPanesWithCustomSkin--; } } } /** * A custom layout manager that is responsible for the layout of * layeredPane, glassPane, menuBar and titlePane, if one has been installed. */ protected class SubstanceRootLayout implements LayoutManager2 { /** * Returns the amount of space the layout would like to have. * * * aram the Container for which this layout manager is being used * * @return a Dimension object containing the layout's preferred size */ @Override 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.getJMenuBar() != null) { mbd = root.getJMenuBar().getPreferredSize(); if (mbd != null) { mbWidth = mbd.width; mbHeight = mbd.height; } } if ((root.getWindowDecorationStyle() != JRootPane.NONE) && (root.getUI() instanceof SubstanceRootPaneUI)) { JComponent titlePane = ((SubstanceRootPaneUI) 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 + tpHeight + i.top + i.bottom); } /** * Returns the minimum amount of space the layout needs. * * * aram the Container for which this layout manager is being used * * @return a Dimension object containing the layout's minimum size */ @Override public Dimension minimumLayoutSize(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().getMinimumSize(); } else { cpd = root.getSize(); } if (cpd != null) { cpWidth = cpd.width; cpHeight = cpd.height; } if (root.getJMenuBar() != null) { mbd = root.getJMenuBar().getMinimumSize(); if (mbd != null) { mbWidth = mbd.width; mbHeight = mbd.height; } } if ((root.getWindowDecorationStyle() != JRootPane.NONE) && (root.getUI() instanceof SubstanceRootPaneUI)) { JComponent titlePane = ((SubstanceRootPaneUI) root.getUI()) .getTitlePane(); if (titlePane != null) { tpd = titlePane.getMinimumSize(); 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 + tpHeight + i.top + i.bottom); } /** * Returns the maximum amount of space the layout can use. * * * aram the Container for which this layout manager is being used * * @return a Dimension object containing the layout's maximum size */ @Override public Dimension maximumLayoutSize(Container target) { Dimension cpd, mbd, tpd; int cpWidth = Integer.MAX_VALUE; int cpHeight = Integer.MAX_VALUE; int mbWidth = Integer.MAX_VALUE; int mbHeight = Integer.MAX_VALUE; int tpWidth = Integer.MAX_VALUE; int tpHeight = Integer.MAX_VALUE; Insets i = target.getInsets(); JRootPane root = (JRootPane) target; if (root.getContentPane() != null) { cpd = root.getContentPane().getMaximumSize(); if (cpd != null) { cpWidth = cpd.width; cpHeight = cpd.height; } } if (root.getJMenuBar() != null) { mbd = root.getJMenuBar().getMaximumSize(); if (mbd != null) { mbWidth = mbd.width; mbHeight = mbd.height; } } if ((root.getWindowDecorationStyle() != JRootPane.NONE) && (root.getUI() instanceof SubstanceRootPaneUI)) { JComponent titlePane = ((SubstanceRootPaneUI) root.getUI()) .getTitlePane(); if (titlePane != null) { tpd = titlePane.getMaximumSize(); if (tpd != null) { tpWidth = tpd.width; tpHeight = tpd.height; } } } int maxHeight = Math.max(Math.max(cpHeight, mbHeight), tpHeight); // Only overflows if 3 real non-MAX_VALUE heights, sum to > // MAX_VALUE // Only will happen if sums to more than 2 billion units. Not // likely. if (maxHeight != Integer.MAX_VALUE) { maxHeight = cpHeight + mbHeight + tpHeight + i.top + i.bottom; } int maxWidth = Math.max(Math.max(cpWidth, mbWidth), tpWidth); // Similar overflow comment as above if (maxWidth != Integer.MAX_VALUE) { maxWidth += i.left + i.right; } return new Dimension(maxWidth, maxHeight); } /** * Instructs the layout manager to perform the layout for the specified * container. * * * aram the Container for which this layout manager is being used */ @Override public void layoutContainer(Container parent) { JRootPane root = (JRootPane) parent; Rectangle b = root.getBounds(); Insets i = root.getInsets(); int nextY = 0; int w = b.width - i.right - i.left; int h = b.height - i.top - i.bottom; if (root.getLayeredPane() != null) { root.getLayeredPane().setBounds(i.left, i.top, w, h); } if (root.getGlassPane() != null) { root.getGlassPane().setBounds(i.left, i.top, w, h); } // Note: This is laying out the children in the layeredPane, // technically, these are not our children. if ((root.getWindowDecorationStyle() != JRootPane.NONE) && (root.getUI() instanceof SubstanceRootPaneUI)) { JComponent titlePane = ((SubstanceRootPaneUI) root.getUI()) .getTitlePane(); if (titlePane != null) { Dimension tpd = titlePane.getPreferredSize(); if (tpd != null) { int tpHeight = tpd.height; titlePane.setBounds(0, 0, w, tpHeight); nextY += tpHeight; } } } if (root.getJMenuBar() != null) { Dimension mbd = root.getJMenuBar().getPreferredSize(); root.getJMenuBar().setBounds(0, nextY, w, mbd.height); nextY += mbd.height; } if (root.getContentPane() != null) { // Dimension cpd = root.getContentPane().getPreferredSize(); root.getContentPane().setBounds(0, nextY, w, h < nextY ? 0 : h - nextY); } } @Override public void addLayoutComponent(String name, Component comp) { } @Override public void removeLayoutComponent(Component comp) { } @Override public void addLayoutComponent(Component comp, Object constraints) { } @Override public float getLayoutAlignmentX(Container target) { return 0.0f; } @Override public float getLayoutAlignmentY(Container target) { return 0.0f; } @Override public void invalidateLayout(Container target) { } } /** * Maps from positions to cursor type. Refer to calculateCorner and * calculatePosition for details of this. */ private static final int[] cursorMapping = new int[] { Cursor.NW_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, Cursor.N_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR, Cursor.NE_RESIZE_CURSOR, Cursor.NW_RESIZE_CURSOR, 0, 0, 0, Cursor.NE_RESIZE_CURSOR, Cursor.W_RESIZE_CURSOR, 0, 0, 0, Cursor.E_RESIZE_CURSOR, Cursor.SW_RESIZE_CURSOR, 0, 0, 0, Cursor.SE_RESIZE_CURSOR, Cursor.SW_RESIZE_CURSOR, Cursor.SW_RESIZE_CURSOR, Cursor.S_RESIZE_CURSOR, Cursor.SE_RESIZE_CURSOR, Cursor.SE_RESIZE_CURSOR }; /** * MouseInputHandler is responsible for handling resize/moving of the * Window. It sets the cursor directly on the Window when then mouse moves * over a hot spot. */ private class MouseInputHandler implements MouseInputListener { /** * Set to true if the drag operation is moving the window. */ private boolean isMovingWindow; /** * Used to determine the corner the resize is occuring from. */ private int dragCursor; /** * X location the mouse went down on for a drag operation. */ private int dragOffsetX; /** * Y location the mouse went down on for a drag operation. */ private int dragOffsetY; /** * Width of the window when the drag started. */ private int dragWidth; /** * Height of the window when the drag started. */ private int dragHeight; /** * PrivilegedExceptionAction needed by mouseDragged method to obtain new * location of window on screen during the drag. */ @SuppressWarnings("unchecked") private final PrivilegedExceptionAction getLocationAction = new PrivilegedExceptionAction() { @Override public Object run() throws HeadlessException { PointerInfo pi = MouseInfo.getPointerInfo(); return pi == null ? null : pi.getLocation(); } }; @Override public void mousePressed(MouseEvent ev) { JRootPane rootPane = SubstanceRootPaneUI.this.getRootPane(); if (rootPane.getWindowDecorationStyle() == JRootPane.NONE) { return; } Point dragWindowOffset = ev.getPoint(); Window w = (Window) ev.getSource(); if (w != null) { w.toFront(); } Point convertedDragWindowOffset = SwingUtilities.convertPoint(w, dragWindowOffset, SubstanceRootPaneUI.this.getTitlePane()); Frame f = null; Dialog d = null; if (w instanceof Frame) { f = (Frame) w; } else if (w instanceof Dialog) { d = (Dialog) w; } int frameState = (f != null) ? f.getExtendedState() : 0; if ((SubstanceRootPaneUI.this.getTitlePane() != null) && SubstanceRootPaneUI.this.getTitlePane().contains( convertedDragWindowOffset)) { if ((((f != null) && ((frameState & Frame.MAXIMIZED_BOTH) == 0)) || (d != null)) && (dragWindowOffset.y >= SubstanceRootPaneUI.BORDER_DRAG_THICKNESS) && (dragWindowOffset.x >= SubstanceRootPaneUI.BORDER_DRAG_THICKNESS) && (dragWindowOffset.x < w.getWidth() - SubstanceRootPaneUI.BORDER_DRAG_THICKNESS)) { this.isMovingWindow = true; this.dragOffsetX = dragWindowOffset.x; this.dragOffsetY = dragWindowOffset.y; } } else if (((f != null) && f.isResizable() && ((frameState & Frame.MAXIMIZED_BOTH) == 0)) || ((d != null) && d.isResizable())) { this.dragOffsetX = dragWindowOffset.x; this.dragOffsetY = dragWindowOffset.y; this.dragWidth = w.getWidth(); this.dragHeight = w.getHeight(); this.dragCursor = this.getCursor(this.calculateCorner(w, dragWindowOffset.x, dragWindowOffset.y)); } } @Override public void mouseReleased(MouseEvent ev) { if ((this.dragCursor != 0) && (SubstanceRootPaneUI.this.window != null) && !SubstanceRootPaneUI.this.window.isValid()) { // Some Window systems validate as you resize, others won't, // thus the check for validity before repainting. SubstanceRootPaneUI.this.window.validate(); SubstanceRootPaneUI.this.getRootPane().repaint(); } this.isMovingWindow = false; this.dragCursor = 0; } @Override public void mouseMoved(MouseEvent ev) { JRootPane root = SubstanceRootPaneUI.this.getRootPane(); if (root.getWindowDecorationStyle() == JRootPane.NONE) { return; } Window w = (Window) ev.getSource(); Frame f = null; Dialog d = null; if (w instanceof Frame) { f = (Frame) w; } else if (w instanceof Dialog) { d = (Dialog) w; } // Update the cursor int cursor = this.getCursor(this.calculateCorner(w, ev.getX(), ev .getY())); if ((cursor != 0) && (((f != null) && (f.isResizable() && ((f .getExtendedState() & Frame.MAXIMIZED_BOTH) == 0))) || ((d != null) && d .isResizable()))) { w.setCursor(Cursor.getPredefinedCursor(cursor)); } else { w.setCursor(SubstanceRootPaneUI.this.lastCursor); } } /** * Adjusts the bounds. * * @param bounds * Original bounds. * @param min * Minimum dimension. * @param deltaX * Delta X. * @param deltaY * Delta Y. * @param deltaWidth * Delta width. * @param deltaHeight * Delta height. */ private void adjust(Rectangle bounds, Dimension min, int deltaX, int deltaY, int deltaWidth, int deltaHeight) { bounds.x += deltaX; bounds.y += deltaY; bounds.width += deltaWidth; bounds.height += deltaHeight; if (min != null) { if (bounds.width < min.width) { int correction = min.width - bounds.width; if (deltaX != 0) { bounds.x -= correction; } bounds.width = min.width; } if (bounds.height < min.height) { int correction = min.height - bounds.height; if (deltaY != 0) { bounds.y -= correction; } bounds.height = min.height; } } } @Override @SuppressWarnings("unchecked") public void mouseDragged(MouseEvent ev) { Window w = (Window) ev.getSource(); Point pt = ev.getPoint(); if (this.isMovingWindow) { Point windowPt; try { windowPt = (Point) AccessController .doPrivileged(this.getLocationAction); if (windowPt != null) { windowPt.x = windowPt.x - this.dragOffsetX; windowPt.y = windowPt.y - this.dragOffsetY; w.setLocation(windowPt); } } catch (PrivilegedActionException ignored) { } } else if (this.dragCursor != 0) { Rectangle r = w.getBounds(); Rectangle startBounds = new Rectangle(r); Dimension min = w.getMinimumSize(); switch (this.dragCursor) { case Cursor.E_RESIZE_CURSOR: this.adjust(r, min, 0, 0, pt.x + (this.dragWidth - this.dragOffsetX) - r.width, 0); break; case Cursor.S_RESIZE_CURSOR: this.adjust(r, min, 0, 0, 0, pt.y + (this.dragHeight - this.dragOffsetY) - r.height); break; case Cursor.N_RESIZE_CURSOR: this.adjust(r, min, 0, pt.y - this.dragOffsetY, 0, -(pt.y - this.dragOffsetY)); break; case Cursor.W_RESIZE_CURSOR: this.adjust(r, min, pt.x - this.dragOffsetX, 0, -(pt.x - this.dragOffsetX), 0); break; case Cursor.NE_RESIZE_CURSOR: this.adjust(r, min, 0, pt.y - this.dragOffsetY, pt.x + (this.dragWidth - this.dragOffsetX) - r.width, -(pt.y - this.dragOffsetY)); break; case Cursor.SE_RESIZE_CURSOR: this.adjust(r, min, 0, 0, pt.x + (this.dragWidth - this.dragOffsetX) - r.width, pt.y + (this.dragHeight - this.dragOffsetY) - r.height); break; case Cursor.NW_RESIZE_CURSOR: this.adjust(r, min, pt.x - this.dragOffsetX, pt.y - this.dragOffsetY, -(pt.x - this.dragOffsetX), -(pt.y - this.dragOffsetY)); break; case Cursor.SW_RESIZE_CURSOR: this.adjust(r, min, pt.x - this.dragOffsetX, 0, -(pt.x - this.dragOffsetX), pt.y + (this.dragHeight - this.dragOffsetY) - r.height); break; default: break; } if (!r.equals(startBounds)) { w.setBounds(r); // Defer repaint/validate on mouseReleased unless dynamic // layout is active. if (Toolkit.getDefaultToolkit().isDynamicLayoutActive()) { w.validate(); SubstanceRootPaneUI.this.getRootPane().repaint(); } } } } private CursorState cursorState = CursorState.NIL; @Override public void mouseEntered(MouseEvent ev) { Window w = (Window) ev.getSource(); if (cursorState == CursorState.EXITED || cursorState == CursorState.NIL) { // fix for defect 107 SubstanceRootPaneUI.this.lastCursor = w.getCursor(); } cursorState = CursorState.ENTERED; this.mouseMoved(ev); } @Override public void mouseExited(MouseEvent ev) { Window w = (Window) ev.getSource(); w.setCursor(SubstanceRootPaneUI.this.lastCursor); cursorState = CursorState.EXITED; } @Override public void mouseClicked(MouseEvent ev) { Window w = (Window) ev.getSource(); Frame f; if (w instanceof Frame) { f = (Frame) w; } else { return; } JComponent windowTitlePane = SubstanceRootPaneUI.this .getTitlePane(); // fix for issue 444 - ignore double clicks when the title pane // is not showing (for example under JRootPane.NONE decoration // style). if (windowTitlePane == null) return; Point convertedPoint = SwingUtilities.convertPoint(w, ev.getPoint(), windowTitlePane); int state = f.getExtendedState(); if ((windowTitlePane != null) && windowTitlePane.contains(convertedPoint)) { if (((ev.getClickCount() % 2) == 0) && ((ev.getModifiers() & InputEvent.BUTTON1_MASK) != 0)) { if (f.isResizable()) { if ((state & Frame.MAXIMIZED_BOTH) != 0) { setMaximized(); f.setExtendedState(state & ~Frame.MAXIMIZED_BOTH); } else { setMaximized(); f.setExtendedState(state | Frame.MAXIMIZED_BOTH); } } } } } /** * Returns the corner that contains the point x, * y, or -1 if the position doesn't match a corner. * * @param w * Window. * @param x * X coordinate. * @param y * Y coordinate. * @return Corner that contains the specified point. */ private int calculateCorner(Window w, int x, int y) { Insets insets = w.getInsets(); int xPosition = this.calculatePosition(x - insets.left, w .getWidth() - insets.left - insets.right); int yPosition = this.calculatePosition(y - insets.top, w .getHeight() - insets.top - insets.bottom); if ((xPosition == -1) || (yPosition == -1)) { return -1; } return yPosition * 5 + xPosition; } /** * Returns the Cursor to render for the specified corner. This returns 0 * if the corner doesn't map to a valid Cursor * * @param corner * Corner * @return Cursor to render for the specified corner. */ private int getCursor(int corner) { if (corner == -1) { return 0; } return SubstanceRootPaneUI.cursorMapping[corner]; } /** * Returns an integer indicating the position of spot in * width. The return value will be: 0 if < * BORDER_DRAG_THICKNESS 1 if < CORNER_DRAG_WIDTH 2 if >= * CORNER_DRAG_WIDTH && < width - BORDER_DRAG_THICKNESS 3 if >= width - * CORNER_DRAG_WIDTH 4 if >= width - BORDER_DRAG_THICKNESS 5 otherwise * * @param spot * Spot. * @param width * Width. * @return The position of spot in width. */ private int calculatePosition(int spot, int width) { if (spot < SubstanceRootPaneUI.BORDER_DRAG_THICKNESS) { return 0; } if (spot < SubstanceRootPaneUI.CORNER_DRAG_WIDTH) { return 1; } if (spot >= (width - SubstanceRootPaneUI.BORDER_DRAG_THICKNESS)) { return 4; } if (spot >= (width - SubstanceRootPaneUI.CORNER_DRAG_WIDTH)) { return 3; } return 2; } } /** * Mouse handler on the title pane. * * @author Kirill Grouchnikov */ private class TitleMouseInputHandler extends MouseInputAdapter { /** * Pointer location when the mouse was pressed for a drag relative to * the upper-lefthand corner of the window. */ private Point dragOffset = new Point(0, 0); @Override public void mousePressed(MouseEvent ev) { JRootPane rootPane = SubstanceRootPaneUI.this.getRootPane(); if (rootPane.getWindowDecorationStyle() == JRootPane.NONE) { return; } Point dragWindowOffset = ev.getPoint(); Component source = (Component) ev.getSource(); Point convertedDragWindowOffset = SwingUtilities.convertPoint( source, dragWindowOffset, getTitlePane()); dragWindowOffset = SwingUtilities.convertPoint(source, dragWindowOffset, SubstanceRootPaneUI.this.window); if (getTitlePane() != null && getTitlePane().contains(convertedDragWindowOffset)) { if (SubstanceRootPaneUI.this.window != null) { SubstanceRootPaneUI.this.window.toFront(); dragOffset = dragWindowOffset; } } } @Override public void mouseDragged(MouseEvent ev) { Component source = (Component) ev.getSource(); // Point pt = SwingUtilities.convertPoint(source, ev.getPoint(), // SubstanceRootPaneUI.this.window); // fix for issue 198 Point eventLocationOnScreen = ev.getLocationOnScreen(); if (eventLocationOnScreen == null) { eventLocationOnScreen = new Point(ev.getX() + source.getLocationOnScreen().x, ev.getY() + source.getLocationOnScreen().y); } // Fix for issue 192 - disable dragging maximized frame. if (SubstanceRootPaneUI.this.window instanceof Frame) { Frame f = (Frame) SubstanceRootPaneUI.this.window; int frameState = (f != null) ? f.getExtendedState() : 0; if ((f != null) && ((frameState & Frame.MAXIMIZED_BOTH) == 0)) { SubstanceRootPaneUI.this.window.setLocation( eventLocationOnScreen.x - dragOffset.x, eventLocationOnScreen.y - dragOffset.y); } } else { // fix for issue 193 - allow dragging decorated dialogs. SubstanceRootPaneUI.this.window.setLocation( eventLocationOnScreen.x - dragOffset.x, eventLocationOnScreen.y - dragOffset.y); } } @Override public void mouseClicked(MouseEvent ev) { Frame f; if (SubstanceRootPaneUI.this.window instanceof Frame) { f = (Frame) SubstanceRootPaneUI.this.window; } else { return; } Point convertedPoint = SwingUtilities.convertPoint( SubstanceRootPaneUI.this.window, ev.getPoint(), SubstanceRootPaneUI.this.getTitlePane()); int state = f.getExtendedState(); if ((SubstanceRootPaneUI.this.getTitlePane() != null) && SubstanceRootPaneUI.this.getTitlePane().contains( convertedPoint)) { if (((ev.getClickCount() % 2) == 0) && ((ev.getModifiers() & InputEvent.BUTTON1_MASK) != 0)) { if (f.isResizable()) { if ((state & Frame.MAXIMIZED_BOTH) != 0) { setMaximized(); f.setExtendedState(state & ~Frame.MAXIMIZED_BOTH); } else { setMaximized(); f.setExtendedState(state | Frame.MAXIMIZED_BOTH); } } } } } } private void propagateModificationState() { JComponent titlePane = getTitlePane(); if (titlePane instanceof SubstanceTitlePane) { ((SubstanceTitlePane) titlePane) .getCloseButton() .putClientProperty( SubstanceLookAndFeel.WINDOW_MODIFIED, root .getClientProperty(SubstanceLookAndFeel.WINDOW_MODIFIED)); return; } JInternalFrame jif = (JInternalFrame) SwingUtilities .getAncestorOfClass(JInternalFrame.class, this.root); if (jif != null) { SubstanceInternalFrameUI internalFrameUI = (SubstanceInternalFrameUI) jif .getUI(); internalFrameUI.setWindowModified(Boolean.TRUE.equals(root .getClientProperty(SubstanceLookAndFeel.WINDOW_MODIFIED))); } } public static boolean hasCustomSkinOnAtLeastOneRootPane() { return (rootPanesWithCustomSkin > 0); } public static ComponentListener WINDOW_ROUNDER = new ComponentAdapter() { @Override public void componentResized(ComponentEvent e) { if (e.getComponent() instanceof Window) { Window w = (Window) e.getComponent(); if ((w instanceof Frame && !((Frame)w).isUndecorated()) || (w instanceof Dialog && !((Dialog)w).isUndecorated())) { return; // don't touch the shape of decorated windows } if (w instanceof RootPaneContainer) { JRootPane jrp = ((RootPaneContainer)w).getRootPane(); if ((jrp.getWindowDecorationStyle() == JRootPane.NONE) || (!SubstanceCoreUtilities.isRoundedCorners(jrp))) { // special case, for undecorated windows and maximized windows AWTUtilities.setWindowShape(w, null); return; } } try { // only round the corners if the screen is reasonably sized, as in // smaller than archival versions of The Godfather, which is at 4096x2160 if (SubstanceCoreUtilities.isRoundedCorners(w) && w.getWidth() * w.getHeight() < (4096*4096)) { AWTUtilities.setWindowShape(w, new RoundRectangle2D.Double(0, 0, w.getWidth(), w.getHeight(), 12, 12)); } else { AWTUtilities.setWindowShape(w, null); } } catch (OutOfMemoryError oome) { AWTUtilities.setWindowShape(w, null); //System.out.println("Rounded panel size on OOOME : " + w.getWidth() + "x" + w.getHeight() + " for an area of " + w.getWidth()*w.getHeight() + "px"); //throw oome; } } } }; // When a JRootPane is created, it hasn't been added to a window yet. // when we are added, set the window to transparent if we are a JDialog or JFrame static HierarchyListener RESIZE_LOADER = new HierarchyListener() { @Override public void hierarchyChanged(HierarchyEvent e) { // if we are not talking about a rootpane being added to a window, quit and never try again if (!((e.getChangedParent() instanceof Dialog) || (e.getChangedParent() instanceof Frame))) { e.getChanged().removeHierarchyListener(this); return; } // if we are something other than a change event, quit if ((e.getID() != HierarchyEvent.HIERARCHY_CHANGED) || !(e.getChanged() instanceof JRootPane)) { return; } Window w = (Window) e.getChangedParent(); if (w != null) { if (!Arrays.asList(w.getComponentListeners()).contains(WINDOW_ROUNDER)) { w.addComponentListener(WINDOW_ROUNDER); } e.getChanged().removeHierarchyListener(this); } } }; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy