LoboJTattoo/src/main/java/com/jtattoo/plaf/BaseRootPaneUI.java
/*
* MIT License
*
* Copyright (c) 2014 - 2024 LoboEvolution
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Contact info: ivan.difrancesco@yahoo.it
*/
package com.jtattoo.plaf;
import javax.swing.*;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicRootPaneUI;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
/**
* This source is a modified copy of javax.swing.plaf.metal.MetalRootPaneUI
* Provides the base look and feel implementation of RootPaneUI.
* <p>
* BaseRootPaneUI provides support for the
* windowDecorationStyle property of JRootPane.
* BaseRootPaneUI does this by way of installing a custom
* LayoutManager, a private Component to render the
* appropriate widgets, and a private Border. The
* LayoutManager is always installed, regardless of the value of
* the windowDecorationStyle property, but the Border
* and Component are only installed/added if the
* windowDecorationStyle is other than JRootPane.NONE.
* <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 TM has been added to the java.beans package. Please
* see {@link java.beans.XMLEncoder}.
*
* @version 1.20 04/27/04
* Author Terry Kellerman
* Author Michael Hagen
* @since 1.4
*/
public class BaseRootPaneUI extends BasicRootPaneUI {
// Konstanten aus javax.swing.JRootPane damit Attribute aus Java 1.4 sich mit
// Java 1.3 uebersetzen lassen
/**
* Constant NONE=0
*/
public static final int NONE = 0;
// ------------------------------------------------------------------------------
/**
* Constant FRAME=1
*/
public static final int FRAME = 1;
/**
* Constant PLAIN_DIALOG=2
*/
public static final int PLAIN_DIALOG = 2;
/**
* Constant INFORMATION_DIALOG=3
*/
public static final int INFORMATION_DIALOG = 3;
/**
* Constant ERROR_DIALOG=4
*/
public static final int ERROR_DIALOG = 4;
/**
* Constant COLOR_CHOOSER_DIALOG=5
*/
public static final int COLOR_CHOOSER_DIALOG = 5;
/**
* Constant FILE_CHOOSER_DIALOG=6
*/
public static final int FILE_CHOOSER_DIALOG = 6;
/**
* Constant QUESTION_DIALOG=7
*/
public static final int QUESTION_DIALOG = 7;
/**
* Constant WARNING_DIALOG=8
*/
public static final int WARNING_DIALOG = 8;
/**
* Constant MAXIMIZED_HORIZ=2
*/
public static final int MAXIMIZED_HORIZ = 2;
/**
* Constant MAXIMIZED_VERT=4
*/
public static final int MAXIMIZED_VERT = 4;
/**
* Constant MAXIMIZED_BOTH=MAXIMIZED_VERT | MAXIMIZED_HORIZ
*/
public static final int MAXIMIZED_BOTH = MAXIMIZED_VERT | MAXIMIZED_HORIZ;
// Konstanten aus java.awt.Frame damit Attribute aus Java 1.4 sich mit Java 1.3
// uebersetzen lassen
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 minimum/maximum size of a Window
*/
private static final Dimension MINIMUM_SIZE = new Dimension(120, 80);
private static final Dimension MAXIMUM_SIZE = Toolkit.getDefaultToolkit().getScreenSize();
/**
* 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;
/**
* 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};
/**
* 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 mouseInputListener;
/**
* WindowListener that is added to the parent Window
* the JRootPane is contained in.
*/
private WindowListener windowListener;
/**
* WindowListener that is added to the parent Window
* the JRootPane is contained in.
*/
private PropertyChangeListener propertyChangeListener;
/**
* 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.
*/
private JRootPane root;
private Cursor savedCursor = null;
/**
* {@inheritDoc}
* <p>
* Creates a UI for a JRootPane.
*/
public static ComponentUI createUI(final JComponent c) {
return new BaseRootPaneUI();
}
/**
* Returns a LayoutManager that will be set on the
* JRootPane.
*
* @return The layout manager
*/
public LayoutManager createLayoutManager() {
return new BaseRootLayout();
}
/**
* Returns the JComponent to render the window decoration style.
*
* @param root The root pane
* @return The title pane
*/
public JComponent createTitlePane(final JRootPane root) {
return new BaseTitlePane(root, this);
}
/**
* Returns a MouseListener that will be added to the
* Window containing the JRootPane.
*
* @param root The root pane
* @return The mouse listener
*/
public MouseInputListener createWindowMouseInputListener(final JRootPane root) {
return new MouseInputHandler();
}
/**
* <p>getRootPane.</p>
*
* @return a {@link javax.swing.JRootPane} object.
*/
public JRootPane getRootPane() {
return root;
}
/**
* Returns the BaseTitlePane 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
*/
public BaseTitlePane getTitlePane() {
if (titlePane instanceof BaseTitlePane) {
return (BaseTitlePane) titlePane;
}
return null;
}
/**
* <p>installBorder.</p>
*
* @param root a {@link javax.swing.JRootPane} object.
*/
public void installBorder(final JRootPane root) {
final int style = root.getWindowDecorationStyle();
if (style == NONE) {
LookAndFeel.uninstallBorder(root);
} else {
LookAndFeel.installBorder(root, borderKeys[style]);
}
}
/**
* <p>installClientDecorations.</p>
*
* @param root a {@link javax.swing.JRootPane} object.
*/
public void installClientDecorations(final JRootPane root) {
installBorder(root);
if (titlePane == null) {
setTitlePane(root, createTitlePane(root));
}
installWindowListeners(root, root.getParent());
installLayout(root);
if (window != null) {
// savedCursor = window.getCursor();
root.revalidate();
root.repaint();
}
}
/**
* Installs the appropriate LayoutManager on the JRootPane to
* render the window decorations.
*
* @param root The root pane
*/
public void installLayout(final JRootPane root) {
if (layoutManager == null) {
layoutManager = createLayoutManager();
}
savedOldLayout = root.getLayout();
root.setLayout(layoutManager);
}
/**
* {@inheritDoc}
*/
@Override
protected void installListeners(final JRootPane root) {
super.installListeners(root);
if (root.getWindowDecorationStyle() == JRootPane.NONE) {
propertyChangeListener = evt -> {
if ("ancestor".equals(evt.getPropertyName())) {
if (getRootPane() != null && getRootPane().getParent() instanceof Window) {
window = (Window) getRootPane().getParent();
windowListener = new WindowAdapter() {
@Override
public void windowActivated(final WindowEvent e) {
if (getRootPane() != null) {
getRootPane().repaint();
}
}
@Override
public void windowDeactivated(final WindowEvent e) {
if (getRootPane() != null) {
getRootPane().repaint();
}
}
};
window.addWindowListener(windowListener);
}
}
};
root.addPropertyChangeListener(propertyChangeListener);
}
}
/**
* {@inheritDoc}
*/
@Override
public void installUI(final JComponent c) {
super.installUI(c);
root = (JRootPane) c;
if (root.getWindowDecorationStyle() != JRootPane.NONE) {
installClientDecorations(root);
}
}
/**
* Installs the necessary Listeners on the parent Window, if there
* is one.
* <p>
* This takes the parent so that cleanup can be done from
* removeNotify, at which point the parent hasn't been reset yet.
*
* @param root The root pane
* @param parent The parent of the JRootPane
*/
public void installWindowListeners(final JRootPane root, final 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);
}
}
private JComponent internalGetTitlePane() {
return titlePane;
}
private boolean isDynamicLayout() {
return AbstractLookAndFeel.getTheme().isDynamicLayout();
}
/**
* {@inheritDoc}
*/
@Override
public void propertyChange(final PropertyChangeEvent e) {
super.propertyChange(e);
final String propertyName = e.getPropertyName();
final JRootPane rp = (JRootPane) e.getSource();
if ("windowDecorationStyle".equals(propertyName)) {
final int style = rp.getWindowDecorationStyle();
// This is potentially more than needs to be done,
// but it rarely happens and makes the install/uninstall process
// simpler. BaseTitlePane also assumes it will be recreated if
// the decoration style changes.
uninstallClientDecorations(rp);
if (style != NONE) {
installClientDecorations(rp);
}
} else if ("ancestor".equals(propertyName)) {
uninstallWindowListeners(rp);
if (rp.getWindowDecorationStyle() != JRootPane.NONE) {
installWindowListeners(rp, rp.getParent());
}
}
}
/**
* 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 the JRootPane where to set the title pane
* @param titlePane the JComponent to use for the window title
* pane.
*/
public void setTitlePane(final JRootPane root, final JComponent titlePane) {
final JComponent oldTitlePane = internalGetTitlePane();
if (oldTitlePane == null && titlePane == null || oldTitlePane != null && oldTitlePane.equals(titlePane)) {
return;
}
final JLayeredPane layeredPane = root.getLayeredPane();
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;
}
/**
* Removes any border that may have been installed.
*
* @param root The root pane
*/
public void uninstallBorder(final JRootPane root) {
LookAndFeel.uninstallBorder(root);
}
/**
* <p>uninstallClientDecorations.</p>
*
* @param root a {@link javax.swing.JRootPane} object.
*/
public void uninstallClientDecorations(final JRootPane root) {
uninstallBorder(root);
uninstallWindowListeners(root);
setTitlePane(root, null);
uninstallLayout(root);
final int style = root.getWindowDecorationStyle();
if (style == NONE) {
root.repaint();
root.revalidate();
}
// Reset the cursor, as we may have changed it to a resize cursor
if (window != null && savedCursor != null) {
window.setCursor(savedCursor);
savedCursor = null;
}
window = null;
}
/**
* <p>uninstallLayout.</p>
*
* @param root a {@link javax.swing.JRootPane} object.
*/
public void uninstallLayout(final JRootPane root) {
if (savedOldLayout != null) {
root.setLayout(savedOldLayout);
savedOldLayout = null;
}
}
/**
* {@inheritDoc}
*/
@Override
protected void uninstallListeners(final JRootPane root) {
super.uninstallListeners(root);
if (root.getWindowDecorationStyle() == JRootPane.NONE) {
if (root.getParent() instanceof Window && windowListener != null) {
window = (Window) root.getParent();
window.removeWindowListener(windowListener);
}
root.removePropertyChangeListener(propertyChangeListener);
}
}
/**
* {@inheritDoc}
*/
@Override
public void uninstallUI(final JComponent c) {
super.uninstallUI(c);
uninstallClientDecorations(root);
layoutManager = null;
mouseInputListener = null;
root = null;
}
/**
* Uninstalls the necessary Listeners on the Window the Listeners
* were last installed on.
*
* @param root The root pane
*/
public void uninstallWindowListeners(final JRootPane root) {
if (window != null) {
window.removeMouseListener(mouseInputListener);
window.removeMouseMotionListener(mouseInputListener);
}
}
// ------------------------------------------------------------------------------
private final static class BaseRootLayout implements LayoutManager2 {
@Override
public void addLayoutComponent(final Component comp, final Object constraints) {
}
@Override
public void addLayoutComponent(final String name, final Component comp) {
}
@Override
public float getLayoutAlignmentX(final Container target) {
return 0.0f;
}
@Override
public float getLayoutAlignmentY(final Container target) {
return 0.0f;
}
@Override
public void invalidateLayout(final Container target) {
}
/**
* Instructs the layout manager to perform the layout for the specified
* container.
*
* @param parent for which this layout manager is being used
*/
@Override
public void layoutContainer(final Container parent) {
final JRootPane root = (JRootPane) parent;
final Rectangle b = root.getBounds();
final Insets i = root.getInsets();
int nextY = 0;
final int w = b.width - i.right - i.left;
final 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) {
if (root.getWindowDecorationStyle() != JRootPane.NONE && root.getUI() instanceof BaseRootPaneUI) {
final JComponent titlePane = ((BaseRootPaneUI) root.getUI()).internalGetTitlePane();
int titleHeight = 0;
if (titlePane != null) {
titleHeight = titlePane.getSize().height;
}
root.getGlassPane().setBounds(i.left, i.top + titleHeight, w, h - titleHeight);
} else {
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 BaseRootPaneUI) {
final JComponent titlePane = ((BaseRootPaneUI) root.getUI()).internalGetTitlePane();
if (titlePane != null) {
final Dimension tpd = titlePane.getPreferredSize();
if (tpd != null) {
final int tpHeight = tpd.height;
titlePane.setBounds(0, 0, w, tpHeight);
nextY += tpHeight;
}
}
}
if (root.getJMenuBar() != null) {
final Dimension mbd = root.getJMenuBar().getPreferredSize();
root.getJMenuBar().setBounds(0, nextY, w, mbd.height);
nextY += mbd.height;
}
if (root.getContentPane() != null) {
root.getContentPane().setBounds(0, nextY, w, h < nextY ? 0 : h - nextY);
}
}
/**
* Returns the maximum amount of space the layout can use.
*
* @param target for which this layout manager is being used
* @return a Dimension object containing the layout's maximum size
*/
@Override
public Dimension maximumLayoutSize(final Container target) {
return MAXIMUM_SIZE;
}
/**
* Returns the minimum amount of space the layout needs.
*
* @param parent for which this layout manager is being used
* @return a Dimension object containing the layout's minimum size
*/
@Override
public Dimension minimumLayoutSize(final Container parent) {
return MINIMUM_SIZE;
}
/**
* Returns the amount of space the layout would like to have.
*
* @param parent for which this layout manager is being used
* @return a Dimension object containing the layout's preferred size
*/
@Override
public Dimension preferredLayoutSize(final Container parent) {
final Dimension cpd;
Dimension mbd;
final Dimension tpd;
int cpWidth = 0;
int cpHeight = 0;
int mbWidth = 0;
int mbHeight = 0;
int tpWidth = 0;
final Insets i = parent.getInsets();
final 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 BaseRootPaneUI) {
final JComponent titlePane = ((BaseRootPaneUI) root.getUI()).internalGetTitlePane();
if (titlePane != null) {
tpd = titlePane.getPreferredSize();
if (tpd != null) {
tpWidth = tpd.width;
}
}
}
return new Dimension(Math.max(Math.max(cpWidth, mbWidth), tpWidth) + i.left + i.right,
cpHeight + mbHeight + tpWidth + i.top + i.bottom);
}
@Override
public void removeLayoutComponent(final Component comp) {
}
}
// ------------------------------------------------------------------------------
private static class ResizingPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = 1L;
private BufferedImage bi = null;
public ResizingPanel(final BufferedImage bi) {
super();
this.bi = bi;
}
@Override
public void paint(final Graphics g) {
super.paint(g);
g.drawImage(bi, 0, 0, null);
}
} // end of class ResizingPanel
/**
* 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 final class MouseInputHandler implements MouseInputListener {
/**
* Set to true if the drag operation is moving the window.
*/
private boolean isMovingWindow;
/**
* Set to true if the drag operation is resizing the window.
*/
private boolean isResizingWindow;
/**
* 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;
private Container savedContentPane = null;
private ResizingPanel resizingPanel = null;
private void adjust(final Rectangle bounds, final Dimension min, final int deltaX, final int deltaY, final int deltaWidth, final int deltaHeight) {
bounds.x += deltaX;
bounds.y += deltaY;
bounds.width += deltaWidth;
bounds.height += deltaHeight;
if (min != null) {
if (bounds.width < min.width) {
final int correction = min.width - bounds.width;
if (deltaX != 0) {
bounds.x -= correction;
}
bounds.width = min.width;
}
if (bounds.height < min.height) {
final int correction = min.height - bounds.height;
if (deltaY != 0) {
bounds.y -= correction;
}
bounds.height = min.height;
}
}
}
/**
* Returns the corner that contains the point x, y, or
* -1 if the position doesn't match a corner.
*/
private int calculateCorner(final Component c, final int x, final int y) {
final int xPosition = calculatePosition(x, c.getWidth());
final int yPosition = calculatePosition(y, c.getHeight());
if (xPosition == -1 || yPosition == -1) {
return -1;
}
return yPosition * 5 + xPosition;
}
/**
* 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
*/
private int calculatePosition(final int spot, final int width) {
if (spot < BORDER_DRAG_THICKNESS) {
return 0;
}
if (spot < CORNER_DRAG_WIDTH) {
return 1;
}
if (spot >= width - BORDER_DRAG_THICKNESS) {
return 4;
}
if (spot >= width - CORNER_DRAG_WIDTH) {
return 3;
}
return 2;
}
/**
* Returns the Cursor to render for the specified corner. This returns 0 if the
* corner doesn't map to a valid Cursor
*/
private int getCursor(final int corner) {
if (corner == -1) {
return 0;
}
return cursorMapping[corner];
}
private int getMinScreenY() {
final GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
final GraphicsDevice[] devices = ge.getScreenDevices();
GraphicsDevice gd = devices[0];
GraphicsConfiguration gc = gd.getDefaultConfiguration();
int minScreenY = gc.getBounds().y + Toolkit.getDefaultToolkit().getScreenInsets(gc).top;
if (devices.length > 1) {
for (int i = 1; i < devices.length; i++) {
gd = devices[i];
gc = gd.getDefaultConfiguration();
minScreenY = Math.min(minScreenY,
gc.getBounds().y + Toolkit.getDefaultToolkit().getScreenInsets(gc).top);
}
}
return minScreenY;
}
@Override
public void mouseClicked(final MouseEvent ev) {
if (ev.getSource() instanceof Window) {
final Window window = (Window) ev.getSource();
if (window instanceof Frame) {
final Frame frame = (Frame) window;
final Point convertedPoint = SwingUtilities.convertPoint(window, ev.getPoint(), internalGetTitlePane());
final int state = frame.getExtendedState();
if (titlePane != null && titlePane instanceof TitlePane && titlePane.contains(convertedPoint)
&& frame.isResizable()) {
if (ev.getClickCount() % 2 == 0 && (ev.getModifiers() & InputEvent.BUTTON1_MASK) != 0) {
if ((state & BaseRootPaneUI.MAXIMIZED_BOTH) != 0) {
((TitlePane) titlePane).restore();
} else {
((TitlePane) titlePane).maximize();
}
}
}
}
}
}
@Override
public void mouseDragged(final MouseEvent ev) {
if (ev.getSource() instanceof Window) {
final Window w = (Window) ev.getSource();
if (w.isShowing()) {
if (w instanceof Frame) {
final Frame frame = (Frame) w;
final int frameState = frame.getExtendedState();
if ((frameState & BaseRootPaneUI.MAXIMIZED_BOTH) != 0) {
if (internalGetTitlePane() instanceof TitlePane) {
final Point pt = ev.getPoint();
final Point dragWindowOffset = ev.getPoint();
final Point convertedDragWindowOffset = SwingUtilities.convertPoint(w, dragWindowOffset,
internalGetTitlePane());
if (internalGetTitlePane().contains(convertedDragWindowOffset)) {
final int ow = w.getWidth();
((TitlePane) internalGetTitlePane()).restore();
final int nw = w.getWidth();
final int nx = pt.x * nw / ow;
final int ny = pt.y;
w.setLocation(nx, ny);
dragOffsetX = nx;
dragOffsetY = ny;
isMovingWindow = true;
for (final PropertyChangeListener pcl : frame.getPropertyChangeListeners()) {
pcl.propertyChange(new PropertyChangeEvent(window, "windowMoving", Boolean.FALSE,
Boolean.FALSE));
}
}
}
}
}
final int minScreenY = getMinScreenY();
if (isMovingWindow) {
final Point location = ev.getLocationOnScreen();
location.x -= dragOffsetX;
location.y = Math.max(minScreenY, location.y - dragOffsetY);
w.setLocation(location);
} else if (dragCursor != 0) {
final Point pt = ev.getPoint();
final Rectangle bounds = w.getBounds();
final Rectangle startBounds = new Rectangle(bounds);
final Dimension min = MINIMUM_SIZE;
switch (dragCursor) {
case Cursor.E_RESIZE_CURSOR:
adjust(bounds, min, 0, 0, pt.x + dragWidth - dragOffsetX - bounds.width, 0);
break;
case Cursor.S_RESIZE_CURSOR:
adjust(bounds, min, 0, 0, 0, pt.y + dragHeight - dragOffsetY - bounds.height);
break;
case Cursor.N_RESIZE_CURSOR:
adjust(bounds, min, 0, pt.y - dragOffsetY, 0, -(pt.y - dragOffsetY));
break;
case Cursor.W_RESIZE_CURSOR:
adjust(bounds, min, pt.x - dragOffsetX, 0, -(pt.x - dragOffsetX), 0);
break;
case Cursor.NE_RESIZE_CURSOR:
adjust(bounds, min, 0, pt.y - dragOffsetY, pt.x + dragWidth - dragOffsetX - bounds.width, -(pt.y - dragOffsetY));
break;
case Cursor.SE_RESIZE_CURSOR:
adjust(bounds, min, 0, 0, pt.x + dragWidth - dragOffsetX - bounds.width, pt.y + dragHeight - dragOffsetY - bounds.height);
break;
case Cursor.NW_RESIZE_CURSOR:
adjust(bounds, min, pt.x - dragOffsetX, pt.y - dragOffsetY, -(pt.x - dragOffsetX), -(pt.y - dragOffsetY));
break;
case Cursor.SW_RESIZE_CURSOR:
adjust(bounds, min, pt.x - dragOffsetX, 0, -(pt.x - dragOffsetX), pt.y + dragHeight - dragOffsetY - bounds.height);
break;
default:
break;
}
if (!bounds.equals(startBounds)) {
if (bounds.y < minScreenY) {
final int delta = minScreenY - bounds.y;
bounds.y = minScreenY;
bounds.height -= delta;
}
w.setBounds(bounds);
w.validate();
}
}
}
}
}
@Override
public void mouseEntered(final MouseEvent ev) {
mouseMoved(ev);
}
@Override
public void mouseExited(final MouseEvent ev) {
if (ev.getSource() instanceof Window && savedCursor != null) {
final Window w = (Window) ev.getSource();
w.setCursor(savedCursor);
savedCursor = null;
}
}
@Override
public void mouseMoved(final MouseEvent ev) {
if (ev.getSource() instanceof Window) {
final JRootPane root = getRootPane();
if (root.getWindowDecorationStyle() != JRootPane.NONE) {
final 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
final int cursor = getCursor(calculateCorner(w, ev.getX(), ev.getY()));
if (!isMovingWindow && cursor != 0
&& (f != null && f.isResizable() && (f.getExtendedState() & BaseRootPaneUI.MAXIMIZED_BOTH) == 0
|| d != null && d.isResizable())) {
if (savedCursor == null) {
savedCursor = w.getCursor();
}
w.setCursor(Cursor.getPredefinedCursor(cursor));
} else if (savedCursor != null) {
w.setCursor(savedCursor);
savedCursor = null;
}
}
}
}
@Override
public void mousePressed(final MouseEvent ev) {
final Window w = (Window) ev.getSource();
final JRootPane root = getRootPane();
if (root.getWindowDecorationStyle() != JRootPane.NONE) {
w.toFront();
final Point dragWindowOffset = ev.getPoint();
final Point convertedDragWindowOffset = SwingUtilities.convertPoint(w, dragWindowOffset, internalGetTitlePane());
Frame f = null;
Dialog d = null;
if (w instanceof Frame) {
f = (Frame) w;
} else if (w instanceof Dialog) {
d = (Dialog) w;
}
final int frameState = f != null ? f.getExtendedState() : 0;
if (internalGetTitlePane() != null && internalGetTitlePane().contains(convertedDragWindowOffset)) {
if ((f != null && (frameState & BaseRootPaneUI.MAXIMIZED_BOTH) == 0 || d != null)
&& dragWindowOffset.y >= BORDER_DRAG_THICKNESS
&& dragWindowOffset.x >= BORDER_DRAG_THICKNESS
&& dragWindowOffset.x < w.getWidth() - BORDER_DRAG_THICKNESS) {
isMovingWindow = true;
dragOffsetX = dragWindowOffset.x;
dragOffsetY = dragWindowOffset.y;
if (window instanceof JFrame) {
final JFrame frame = (JFrame) window;
for (final PropertyChangeListener pcl : frame.getPropertyChangeListeners()) {
pcl.propertyChange(new PropertyChangeEvent(window, "windowMoving", Boolean.FALSE, Boolean.FALSE));
}
}
if (window instanceof JDialog) {
final JDialog dialog = (JDialog) window;
for (final PropertyChangeListener pcl : dialog.getPropertyChangeListeners()) {
pcl.propertyChange(new PropertyChangeEvent(window, "windowMoving", Boolean.FALSE, Boolean.FALSE));
}
}
}
} else if (f != null && f.isResizable() && (frameState & BaseRootPaneUI.MAXIMIZED_BOTH) == 0
|| d != null && d.isResizable()) {
isResizingWindow = true;
if (!isDynamicLayout()) {
savedContentPane = getRootPane().getContentPane();
final GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
final BufferedImage bi = gc.createCompatibleImage(savedContentPane.getWidth(), savedContentPane.getHeight());
savedContentPane.paint(bi.getGraphics());
resizingPanel = new ResizingPanel(bi);
getRootPane().setContentPane(resizingPanel);
}
dragOffsetX = dragWindowOffset.x;
dragOffsetY = dragWindowOffset.y;
dragWidth = w.getWidth();
dragHeight = w.getHeight();
dragCursor = getCursor(calculateCorner(w, dragWindowOffset.x, dragWindowOffset.y));
if (window instanceof JFrame) {
final JFrame frame = (JFrame) window;
for (final PropertyChangeListener pcl : frame.getPropertyChangeListeners()) {
pcl.propertyChange(new PropertyChangeEvent(window, "windowResizing", Boolean.FALSE, Boolean.FALSE));
}
}
if (window instanceof JDialog) {
final JDialog dialog = (JDialog) window;
for (final PropertyChangeListener pcl : dialog.getPropertyChangeListeners()) {
pcl.propertyChange(new PropertyChangeEvent(window, "windowResizing", Boolean.FALSE, Boolean.FALSE));
}
}
}
}
}
@Override
public void mouseReleased(final MouseEvent ev) {
if (ev.getSource() instanceof Window) {
final Window w = (Window) ev.getSource();
if (w != null) {
if (!isDynamicLayout() && isResizingWindow) {
getRootPane().setContentPane(savedContentPane);
getRootPane().updateUI();
resizingPanel = null;
} else if (dragCursor != 0 && !window.isValid()) {
// Some Window systems validate as you resize, others won't,
// thus the check for validity before repainting.
w.validate();
getRootPane().repaint();
}
if (window instanceof JFrame) {
final JFrame frame = (JFrame) window;
for (final PropertyChangeListener pcl : frame.getPropertyChangeListeners()) {
if (isMovingWindow) {
pcl.propertyChange(
new PropertyChangeEvent(window, "windowMoved", Boolean.FALSE, Boolean.FALSE));
} else {
pcl.propertyChange(
new PropertyChangeEvent(window, "windowResized", Boolean.FALSE, Boolean.FALSE));
}
}
}
if (window instanceof JDialog) {
final JDialog dialog = (JDialog) window;
for (final PropertyChangeListener pcl : dialog.getPropertyChangeListeners()) {
if (isMovingWindow) {
pcl.propertyChange(
new PropertyChangeEvent(window, "windowMoved", Boolean.FALSE, Boolean.FALSE));
} else {
pcl.propertyChange(
new PropertyChangeEvent(window, "windowResized", Boolean.FALSE, Boolean.FALSE));
}
}
}
}
isMovingWindow = false;
isResizingWindow = false;
dragCursor = 0;
}
}
}
} // end of class BaseRootPaneUI