You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
816 lines
28 KiB
816 lines
28 KiB
/*
|
|
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
package javax.swing;
|
|
|
|
import com.sun.awt.AWTUtilities;
|
|
import sun.awt.AWTAccessor;
|
|
import sun.awt.SunToolkit;
|
|
|
|
import java.awt.*;
|
|
import java.beans.PropertyVetoException;
|
|
|
|
/** This is an implementation of the <code>DesktopManager</code>.
|
|
* It currently implements the basic behaviors for managing
|
|
* <code>JInternalFrame</code>s in an arbitrary parent.
|
|
* <code>JInternalFrame</code>s that are not children of a
|
|
* <code>JDesktop</code> will use this component
|
|
* to handle their desktop-like actions.
|
|
* <p>This class provides a policy for the various JInternalFrame methods,
|
|
* it is not meant to be called directly rather the various JInternalFrame
|
|
* methods will call into the DesktopManager.</p>
|
|
* @see JDesktopPane
|
|
* @see JInternalFrame
|
|
* @author David Kloba
|
|
* @author Steve Wilson
|
|
*/
|
|
public class DefaultDesktopManager implements DesktopManager, java.io.Serializable {
|
|
final static String HAS_BEEN_ICONIFIED_PROPERTY = "wasIconOnce";
|
|
|
|
final static int DEFAULT_DRAG_MODE = 0;
|
|
final static int OUTLINE_DRAG_MODE = 1;
|
|
final static int FASTER_DRAG_MODE = 2;
|
|
|
|
int dragMode = DEFAULT_DRAG_MODE;
|
|
|
|
private transient Rectangle currentBounds = null;
|
|
private transient Graphics desktopGraphics = null;
|
|
private transient Rectangle desktopBounds = null;
|
|
private transient Rectangle[] floatingItems = {};
|
|
|
|
/**
|
|
* Set to true when the user actually drags a frame vs clicks on it
|
|
* to start the drag operation. This is only used when dragging with
|
|
* FASTER_DRAG_MODE.
|
|
*/
|
|
private transient boolean didDrag;
|
|
|
|
/** Normally this method will not be called. If it is, it
|
|
* try to determine the appropriate parent from the desktopIcon of the frame.
|
|
* Will remove the desktopIcon from its parent if it successfully adds the frame.
|
|
*/
|
|
public void openFrame(JInternalFrame f) {
|
|
if(f.getDesktopIcon().getParent() != null) {
|
|
f.getDesktopIcon().getParent().add(f);
|
|
removeIconFor(f);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes the frame, and, if necessary, the
|
|
* <code>desktopIcon</code>, from its parent.
|
|
* @param f the <code>JInternalFrame</code> to be removed
|
|
*/
|
|
public void closeFrame(JInternalFrame f) {
|
|
JDesktopPane d = f.getDesktopPane();
|
|
if (d == null) {
|
|
return;
|
|
}
|
|
boolean findNext = f.isSelected();
|
|
Container c = f.getParent();
|
|
JInternalFrame nextFrame = null;
|
|
if (findNext) {
|
|
nextFrame = d.getNextFrame(f);
|
|
try { f.setSelected(false); } catch (PropertyVetoException e2) { }
|
|
}
|
|
if(c != null) {
|
|
c.remove(f); // Removes the focus.
|
|
c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight());
|
|
}
|
|
removeIconFor(f);
|
|
if(f.getNormalBounds() != null)
|
|
f.setNormalBounds(null);
|
|
if(wasIcon(f))
|
|
setWasIcon(f, null);
|
|
if (nextFrame != null) {
|
|
try { nextFrame.setSelected(true); }
|
|
catch (PropertyVetoException e2) { }
|
|
} else if (findNext && d.getComponentCount() == 0) {
|
|
// It was selected and was the last component on the desktop.
|
|
d.requestFocus();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Resizes the frame to fill its parents bounds.
|
|
* @param f the frame to be resized
|
|
*/
|
|
public void maximizeFrame(JInternalFrame f) {
|
|
if (f.isIcon()) {
|
|
try {
|
|
// In turn calls deiconifyFrame in the desktop manager.
|
|
// That method will handle the maximization of the frame.
|
|
f.setIcon(false);
|
|
} catch (PropertyVetoException e2) {
|
|
}
|
|
} else {
|
|
f.setNormalBounds(f.getBounds());
|
|
Rectangle desktopBounds = f.getParent().getBounds();
|
|
setBoundsForFrame(f, 0, 0,
|
|
desktopBounds.width, desktopBounds.height);
|
|
}
|
|
|
|
// Set the maximized frame as selected.
|
|
try {
|
|
f.setSelected(true);
|
|
} catch (PropertyVetoException e2) {
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Restores the frame back to its size and position prior
|
|
* to a <code>maximizeFrame</code> call.
|
|
* @param f the <code>JInternalFrame</code> to be restored
|
|
*/
|
|
public void minimizeFrame(JInternalFrame f) {
|
|
// If the frame was an icon restore it back to an icon.
|
|
if (f.isIcon()) {
|
|
iconifyFrame(f);
|
|
return;
|
|
}
|
|
|
|
if ((f.getNormalBounds()) != null) {
|
|
Rectangle r = f.getNormalBounds();
|
|
f.setNormalBounds(null);
|
|
try { f.setSelected(true); } catch (PropertyVetoException e2) { }
|
|
setBoundsForFrame(f, r.x, r.y, r.width, r.height);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes the frame from its parent and adds its
|
|
* <code>desktopIcon</code> to the parent.
|
|
* @param f the <code>JInternalFrame</code> to be iconified
|
|
*/
|
|
public void iconifyFrame(JInternalFrame f) {
|
|
JInternalFrame.JDesktopIcon desktopIcon;
|
|
Container c = f.getParent();
|
|
JDesktopPane d = f.getDesktopPane();
|
|
boolean findNext = f.isSelected();
|
|
desktopIcon = f.getDesktopIcon();
|
|
if(!wasIcon(f)) {
|
|
Rectangle r = getBoundsForIconOf(f);
|
|
desktopIcon.setBounds(r.x, r.y, r.width, r.height);
|
|
// we must validate the hierarchy to not break the hw/lw mixing
|
|
desktopIcon.revalidate();
|
|
setWasIcon(f, Boolean.TRUE);
|
|
}
|
|
|
|
if (c == null || d == null) {
|
|
return;
|
|
}
|
|
|
|
if (c instanceof JLayeredPane) {
|
|
JLayeredPane lp = (JLayeredPane)c;
|
|
int layer = lp.getLayer(f);
|
|
lp.putLayer(desktopIcon, layer);
|
|
}
|
|
|
|
// If we are maximized we already have the normal bounds recorded
|
|
// don't try to re-record them, otherwise we incorrectly set the
|
|
// normal bounds to maximized state.
|
|
if (!f.isMaximum()) {
|
|
f.setNormalBounds(f.getBounds());
|
|
}
|
|
d.setComponentOrderCheckingEnabled(false);
|
|
c.remove(f);
|
|
c.add(desktopIcon);
|
|
d.setComponentOrderCheckingEnabled(true);
|
|
c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight());
|
|
if (findNext) {
|
|
if (d.selectFrame(true) == null) {
|
|
// The icon is the last frame.
|
|
f.restoreSubcomponentFocus();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Removes the desktopIcon from its parent and adds its frame
|
|
* to the parent.
|
|
* @param f the <code>JInternalFrame</code> to be de-iconified
|
|
*/
|
|
public void deiconifyFrame(JInternalFrame f) {
|
|
JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon();
|
|
Container c = desktopIcon.getParent();
|
|
JDesktopPane d = f.getDesktopPane();
|
|
if (c != null && d != null) {
|
|
c.add(f);
|
|
// If the frame is to be restored to a maximized state make
|
|
// sure it still fills the whole desktop.
|
|
if (f.isMaximum()) {
|
|
Rectangle desktopBounds = c.getBounds();
|
|
if (f.getWidth() != desktopBounds.width ||
|
|
f.getHeight() != desktopBounds.height) {
|
|
setBoundsForFrame(f, 0, 0,
|
|
desktopBounds.width, desktopBounds.height);
|
|
}
|
|
}
|
|
removeIconFor(f);
|
|
if (f.isSelected()) {
|
|
f.moveToFront();
|
|
f.restoreSubcomponentFocus();
|
|
}
|
|
else {
|
|
try {
|
|
f.setSelected(true);
|
|
} catch (PropertyVetoException e2) {}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/** This will activate <b>f</b> moving it to the front. It will
|
|
* set the current active frame's (if any)
|
|
* <code>IS_SELECTED_PROPERTY</code> to <code>false</code>.
|
|
* There can be only one active frame across all Layers.
|
|
* @param f the <code>JInternalFrame</code> to be activated
|
|
*/
|
|
public void activateFrame(JInternalFrame f) {
|
|
Container p = f.getParent();
|
|
Component[] c;
|
|
JDesktopPane d = f.getDesktopPane();
|
|
JInternalFrame currentlyActiveFrame =
|
|
(d == null) ? null : d.getSelectedFrame();
|
|
// fix for bug: 4162443
|
|
if(p == null) {
|
|
// If the frame is not in parent, its icon maybe, check it
|
|
p = f.getDesktopIcon().getParent();
|
|
if(p == null)
|
|
return;
|
|
}
|
|
// we only need to keep track of the currentActive InternalFrame, if any
|
|
if (currentlyActiveFrame == null){
|
|
if (d != null) { d.setSelectedFrame(f);}
|
|
} else if (currentlyActiveFrame != f) {
|
|
// if not the same frame as the current active
|
|
// we deactivate the current
|
|
if (currentlyActiveFrame.isSelected()) {
|
|
try {
|
|
currentlyActiveFrame.setSelected(false);
|
|
}
|
|
catch(PropertyVetoException e2) {}
|
|
}
|
|
if (d != null) { d.setSelectedFrame(f);}
|
|
}
|
|
f.moveToFront();
|
|
}
|
|
|
|
// implements javax.swing.DesktopManager
|
|
public void deactivateFrame(JInternalFrame f) {
|
|
JDesktopPane d = f.getDesktopPane();
|
|
JInternalFrame currentlyActiveFrame =
|
|
(d == null) ? null : d.getSelectedFrame();
|
|
if (currentlyActiveFrame == f)
|
|
d.setSelectedFrame(null);
|
|
}
|
|
|
|
// implements javax.swing.DesktopManager
|
|
public void beginDraggingFrame(JComponent f) {
|
|
setupDragMode(f);
|
|
|
|
if (dragMode == FASTER_DRAG_MODE) {
|
|
Component desktop = f.getParent();
|
|
floatingItems = findFloatingItems(f);
|
|
currentBounds = f.getBounds();
|
|
if (desktop instanceof JComponent) {
|
|
desktopBounds = ((JComponent)desktop).getVisibleRect();
|
|
}
|
|
else {
|
|
desktopBounds = desktop.getBounds();
|
|
desktopBounds.x = desktopBounds.y = 0;
|
|
}
|
|
desktopGraphics = JComponent.safelyGetGraphics(desktop);
|
|
((JInternalFrame)f).isDragging = true;
|
|
didDrag = false;
|
|
}
|
|
|
|
}
|
|
|
|
private void setupDragMode(JComponent f) {
|
|
JDesktopPane p = getDesktopPane(f);
|
|
Container parent = f.getParent();
|
|
dragMode = DEFAULT_DRAG_MODE;
|
|
if (p != null) {
|
|
String mode = (String)p.getClientProperty("JDesktopPane.dragMode");
|
|
Window window = SwingUtilities.getWindowAncestor(f);
|
|
if (window != null && !AWTUtilities.isWindowOpaque(window)) {
|
|
dragMode = DEFAULT_DRAG_MODE;
|
|
} else if (mode != null && mode.equals("outline")) {
|
|
dragMode = OUTLINE_DRAG_MODE;
|
|
} else if (mode != null && mode.equals("faster")
|
|
&& f instanceof JInternalFrame
|
|
&& ((JInternalFrame)f).isOpaque() &&
|
|
(parent == null || parent.isOpaque())) {
|
|
dragMode = FASTER_DRAG_MODE;
|
|
} else {
|
|
if (p.getDragMode() == JDesktopPane.OUTLINE_DRAG_MODE ) {
|
|
dragMode = OUTLINE_DRAG_MODE;
|
|
} else if ( p.getDragMode() == JDesktopPane.LIVE_DRAG_MODE
|
|
&& f instanceof JInternalFrame
|
|
&& ((JInternalFrame)f).isOpaque()) {
|
|
dragMode = FASTER_DRAG_MODE;
|
|
} else {
|
|
dragMode = DEFAULT_DRAG_MODE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private transient Point currentLoc = null;
|
|
|
|
/**
|
|
* Moves the visible location of the frame being dragged
|
|
* to the location specified. The means by which this occurs can vary depending
|
|
* on the dragging algorithm being used. The actual logical location of the frame
|
|
* might not change until <code>endDraggingFrame</code> is called.
|
|
*/
|
|
public void dragFrame(JComponent f, int newX, int newY) {
|
|
|
|
if (dragMode == OUTLINE_DRAG_MODE) {
|
|
JDesktopPane desktopPane = getDesktopPane(f);
|
|
if (desktopPane != null){
|
|
Graphics g = JComponent.safelyGetGraphics(desktopPane);
|
|
|
|
g.setXORMode(Color.white);
|
|
if (currentLoc != null) {
|
|
g.drawRect(currentLoc.x, currentLoc.y,
|
|
f.getWidth()-1, f.getHeight()-1);
|
|
}
|
|
g.drawRect( newX, newY, f.getWidth()-1, f.getHeight()-1);
|
|
/* Work around for 6635462: XOR mode may cause a SurfaceLost on first use.
|
|
* Swing doesn't expect that its XOR drawRect did
|
|
* not complete, so believes that on re-entering at
|
|
* the next update location, that there is an XOR rect
|
|
* to draw out at "currentLoc". But in fact
|
|
* its now got a new clean surface without that rect,
|
|
* so drawing it "out" in fact draws it on, leaving garbage.
|
|
* So only update/set currentLoc if the draw completed.
|
|
*/
|
|
sun.java2d.SurfaceData sData =
|
|
((sun.java2d.SunGraphics2D)g).getSurfaceData();
|
|
|
|
if (!sData.isSurfaceLost()) {
|
|
currentLoc = new Point (newX, newY);
|
|
}
|
|
;
|
|
g.dispose();
|
|
}
|
|
} else if (dragMode == FASTER_DRAG_MODE) {
|
|
dragFrameFaster(f, newX, newY);
|
|
} else {
|
|
setBoundsForFrame(f, newX, newY, f.getWidth(), f.getHeight());
|
|
}
|
|
}
|
|
|
|
// implements javax.swing.DesktopManager
|
|
public void endDraggingFrame(JComponent f) {
|
|
if ( dragMode == OUTLINE_DRAG_MODE && currentLoc != null) {
|
|
setBoundsForFrame(f, currentLoc.x, currentLoc.y, f.getWidth(), f.getHeight() );
|
|
currentLoc = null;
|
|
} else if (dragMode == FASTER_DRAG_MODE) {
|
|
currentBounds = null;
|
|
if (desktopGraphics != null) {
|
|
desktopGraphics.dispose();
|
|
desktopGraphics = null;
|
|
}
|
|
desktopBounds = null;
|
|
((JInternalFrame)f).isDragging = false;
|
|
}
|
|
}
|
|
|
|
// implements javax.swing.DesktopManager
|
|
public void beginResizingFrame(JComponent f, int direction) {
|
|
setupDragMode(f);
|
|
}
|
|
|
|
/**
|
|
* Calls <code>setBoundsForFrame</code> with the new values.
|
|
* @param f the component to be resized
|
|
* @param newX the new x-coordinate
|
|
* @param newY the new y-coordinate
|
|
* @param newWidth the new width
|
|
* @param newHeight the new height
|
|
*/
|
|
public void resizeFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
|
|
|
|
if ( dragMode == DEFAULT_DRAG_MODE || dragMode == FASTER_DRAG_MODE ) {
|
|
setBoundsForFrame(f, newX, newY, newWidth, newHeight);
|
|
} else {
|
|
JDesktopPane desktopPane = getDesktopPane(f);
|
|
if (desktopPane != null){
|
|
Graphics g = JComponent.safelyGetGraphics(desktopPane);
|
|
|
|
g.setXORMode(Color.white);
|
|
if (currentBounds != null) {
|
|
g.drawRect( currentBounds.x, currentBounds.y, currentBounds.width-1, currentBounds.height-1);
|
|
}
|
|
g.drawRect( newX, newY, newWidth-1, newHeight-1);
|
|
|
|
// Work around for 6635462, see comment in dragFrame()
|
|
sun.java2d.SurfaceData sData =
|
|
((sun.java2d.SunGraphics2D)g).getSurfaceData();
|
|
if (!sData.isSurfaceLost()) {
|
|
currentBounds = new Rectangle (newX, newY, newWidth, newHeight);
|
|
}
|
|
|
|
g.setPaintMode();
|
|
g.dispose();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// implements javax.swing.DesktopManager
|
|
public void endResizingFrame(JComponent f) {
|
|
if ( dragMode == OUTLINE_DRAG_MODE && currentBounds != null) {
|
|
setBoundsForFrame(f, currentBounds.x, currentBounds.y, currentBounds.width, currentBounds.height );
|
|
currentBounds = null;
|
|
}
|
|
}
|
|
|
|
|
|
/** This moves the <code>JComponent</code> and repaints the damaged areas. */
|
|
public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) {
|
|
f.setBounds(newX, newY, newWidth, newHeight);
|
|
// we must validate the hierarchy to not break the hw/lw mixing
|
|
f.revalidate();
|
|
}
|
|
|
|
/** Convenience method to remove the desktopIcon of <b>f</b> is necessary. */
|
|
protected void removeIconFor(JInternalFrame f) {
|
|
JInternalFrame.JDesktopIcon di = f.getDesktopIcon();
|
|
Container c = di.getParent();
|
|
if(c != null) {
|
|
c.remove(di);
|
|
c.repaint(di.getX(), di.getY(), di.getWidth(), di.getHeight());
|
|
}
|
|
}
|
|
|
|
/** The iconifyFrame() code calls this to determine the proper bounds
|
|
* for the desktopIcon.
|
|
*/
|
|
|
|
protected Rectangle getBoundsForIconOf(JInternalFrame f) {
|
|
//
|
|
// Get the icon for this internal frame and its preferred size
|
|
//
|
|
|
|
JInternalFrame.JDesktopIcon icon = f.getDesktopIcon();
|
|
Dimension prefSize = icon.getPreferredSize();
|
|
//
|
|
// Get the parent bounds and child components.
|
|
//
|
|
|
|
Container c = f.getParent();
|
|
if (c == null) {
|
|
c = f.getDesktopIcon().getParent();
|
|
}
|
|
|
|
if (c == null) {
|
|
/* the frame has not yet been added to the parent; how about (0,0) ?*/
|
|
return new Rectangle(0, 0, prefSize.width, prefSize.height);
|
|
}
|
|
|
|
Rectangle parentBounds = c.getBounds();
|
|
Component [] components = c.getComponents();
|
|
|
|
|
|
//
|
|
// Iterate through valid default icon locations and return the
|
|
// first one that does not intersect any other icons.
|
|
//
|
|
|
|
Rectangle availableRectangle = null;
|
|
JInternalFrame.JDesktopIcon currentIcon = null;
|
|
|
|
int x = 0;
|
|
int y = parentBounds.height - prefSize.height;
|
|
int w = prefSize.width;
|
|
int h = prefSize.height;
|
|
|
|
boolean found = false;
|
|
|
|
while (!found) {
|
|
|
|
availableRectangle = new Rectangle(x,y,w,h);
|
|
|
|
found = true;
|
|
|
|
for ( int i=0; i<components.length; i++ ) {
|
|
|
|
//
|
|
// Get the icon for this component
|
|
//
|
|
|
|
if ( components[i] instanceof JInternalFrame ) {
|
|
currentIcon = ((JInternalFrame)components[i]).getDesktopIcon();
|
|
}
|
|
else if ( components[i] instanceof JInternalFrame.JDesktopIcon ){
|
|
currentIcon = (JInternalFrame.JDesktopIcon)components[i];
|
|
} else
|
|
/* found a child that's neither an internal frame nor
|
|
an icon. I don't believe this should happen, but at
|
|
present it does and causes a null pointer exception.
|
|
Even when that gets fixed, this code protects against
|
|
the npe. hania */
|
|
continue;
|
|
|
|
//
|
|
// If this icon intersects the current location, get next location.
|
|
//
|
|
|
|
if ( !currentIcon.equals(icon) ) {
|
|
if ( availableRectangle.intersects(currentIcon.getBounds()) ) {
|
|
found = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (currentIcon == null)
|
|
/* didn't find any useful children above. This probably shouldn't
|
|
happen, but this check protects against an npe if it ever does
|
|
(and it's happening now) */
|
|
return availableRectangle;
|
|
|
|
x += currentIcon.getBounds().width;
|
|
|
|
if ( x + w > parentBounds.width ) {
|
|
x = 0;
|
|
y -= h;
|
|
}
|
|
}
|
|
|
|
return(availableRectangle);
|
|
}
|
|
|
|
/**
|
|
* Stores the bounds of the component just before a maximize call.
|
|
* @param f the component about to be resized
|
|
* @param r the normal bounds to be saved away
|
|
*/
|
|
protected void setPreviousBounds(JInternalFrame f, Rectangle r) {
|
|
f.setNormalBounds(r);
|
|
}
|
|
|
|
/**
|
|
* Gets the normal bounds of the component prior to the component
|
|
* being maximized.
|
|
* @param f the <code>JInternalFrame</code> of interest
|
|
* @return the normal bounds of the component
|
|
*/
|
|
protected Rectangle getPreviousBounds(JInternalFrame f) {
|
|
return f.getNormalBounds();
|
|
}
|
|
|
|
/**
|
|
* Sets that the component has been iconized and the bounds of the
|
|
* <code>desktopIcon</code> are valid.
|
|
*/
|
|
protected void setWasIcon(JInternalFrame f, Boolean value) {
|
|
if (value != null) {
|
|
f.putClientProperty(HAS_BEEN_ICONIFIED_PROPERTY, value);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns <code>true</code> if the component has been iconized
|
|
* and the bounds of the <code>desktopIcon</code> are valid,
|
|
* otherwise returns <code>false</code>.
|
|
*
|
|
* @param f the <code>JInternalFrame</code> of interest
|
|
* @return <code>true</code> if the component has been iconized;
|
|
* otherwise returns <code>false</code>
|
|
*/
|
|
protected boolean wasIcon(JInternalFrame f) {
|
|
return (f.getClientProperty(HAS_BEEN_ICONIFIED_PROPERTY) == Boolean.TRUE);
|
|
}
|
|
|
|
|
|
JDesktopPane getDesktopPane( JComponent frame ) {
|
|
JDesktopPane pane = null;
|
|
Component c = frame.getParent();
|
|
|
|
// Find the JDesktopPane
|
|
while ( pane == null ) {
|
|
if ( c instanceof JDesktopPane ) {
|
|
pane = (JDesktopPane)c;
|
|
}
|
|
else if ( c == null ) {
|
|
break;
|
|
}
|
|
else {
|
|
c = c.getParent();
|
|
}
|
|
}
|
|
|
|
return pane;
|
|
}
|
|
|
|
|
|
// =========== stuff for faster frame dragging ===================
|
|
|
|
private void dragFrameFaster(JComponent f, int newX, int newY) {
|
|
|
|
Rectangle previousBounds = new Rectangle(currentBounds.x,
|
|
currentBounds.y,
|
|
currentBounds.width,
|
|
currentBounds.height);
|
|
|
|
// move the frame
|
|
currentBounds.x = newX;
|
|
currentBounds.y = newY;
|
|
|
|
if (didDrag) {
|
|
// Only initiate cleanup if we have actually done a drag.
|
|
emergencyCleanup(f);
|
|
}
|
|
else {
|
|
didDrag = true;
|
|
// We reset the danger field as until now we haven't actually
|
|
// moved the internal frame so we don't need to initiate repaint.
|
|
((JInternalFrame)f).danger = false;
|
|
}
|
|
|
|
boolean floaterCollision = isFloaterCollision(previousBounds, currentBounds);
|
|
|
|
JComponent parent = (JComponent)f.getParent();
|
|
Rectangle visBounds = previousBounds.intersection(desktopBounds);
|
|
|
|
RepaintManager currentManager = RepaintManager.currentManager(f);
|
|
|
|
currentManager.beginPaint();
|
|
try {
|
|
if(!floaterCollision) {
|
|
currentManager.copyArea(parent, desktopGraphics, visBounds.x,
|
|
visBounds.y,
|
|
visBounds.width,
|
|
visBounds.height,
|
|
newX - previousBounds.x,
|
|
newY - previousBounds.y,
|
|
true);
|
|
}
|
|
|
|
f.setBounds(currentBounds);
|
|
|
|
if (!floaterCollision) {
|
|
Rectangle r = currentBounds;
|
|
currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height);
|
|
}
|
|
|
|
if(floaterCollision) {
|
|
// since we couldn't blit we just redraw as fast as possible
|
|
// the isDragging mucking is to avoid activating emergency
|
|
// cleanup
|
|
((JInternalFrame)f).isDragging = false;
|
|
parent.paintImmediately(currentBounds);
|
|
((JInternalFrame)f).isDragging = true;
|
|
}
|
|
|
|
// fake out the repaint manager. We'll take care of everything
|
|
|
|
currentManager.markCompletelyClean(parent);
|
|
currentManager.markCompletelyClean(f);
|
|
|
|
// compute the minimal newly exposed area
|
|
// if the rects intersect then we use computeDifference. Otherwise
|
|
// we'll repaint the entire previous bounds
|
|
Rectangle[] dirtyRects = null;
|
|
if ( previousBounds.intersects(currentBounds) ) {
|
|
dirtyRects = SwingUtilities.computeDifference(previousBounds,
|
|
currentBounds);
|
|
} else {
|
|
dirtyRects = new Rectangle[1];
|
|
dirtyRects[0] = previousBounds;
|
|
};
|
|
|
|
// Fix the damage
|
|
for (int i = 0; i < dirtyRects.length; i++) {
|
|
parent.paintImmediately(dirtyRects[i]);
|
|
Rectangle r = dirtyRects[i];
|
|
currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height);
|
|
}
|
|
|
|
// new areas of blit were exposed
|
|
if ( !(visBounds.equals(previousBounds)) ) {
|
|
dirtyRects = SwingUtilities.computeDifference(previousBounds,
|
|
desktopBounds);
|
|
for (int i = 0; i < dirtyRects.length; i++) {
|
|
dirtyRects[i].x += newX - previousBounds.x;
|
|
dirtyRects[i].y += newY - previousBounds.y;
|
|
((JInternalFrame)f).isDragging = false;
|
|
parent.paintImmediately(dirtyRects[i]);
|
|
((JInternalFrame)f).isDragging = true;
|
|
Rectangle r = dirtyRects[i];
|
|
currentManager.notifyRepaintPerformed(parent, r.x, r.y, r.width, r.height);
|
|
}
|
|
|
|
}
|
|
} finally {
|
|
currentManager.endPaint();
|
|
}
|
|
|
|
// update window if it's non-opaque
|
|
Window topLevel = SwingUtilities.getWindowAncestor(f);
|
|
Toolkit tk = Toolkit.getDefaultToolkit();
|
|
if (!topLevel.isOpaque() &&
|
|
(tk instanceof SunToolkit) &&
|
|
((SunToolkit)tk).needUpdateWindow())
|
|
{
|
|
AWTAccessor.getWindowAccessor().updateWindow(topLevel);
|
|
}
|
|
}
|
|
|
|
private boolean isFloaterCollision(Rectangle moveFrom, Rectangle moveTo) {
|
|
if (floatingItems.length == 0) {
|
|
// System.out.println("no floaters");
|
|
return false;
|
|
}
|
|
|
|
for (int i = 0; i < floatingItems.length; i++) {
|
|
boolean intersectsFrom = moveFrom.intersects(floatingItems[i]);
|
|
if (intersectsFrom) {
|
|
return true;
|
|
}
|
|
boolean intersectsTo = moveTo.intersects(floatingItems[i]);
|
|
if (intersectsTo) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private Rectangle[] findFloatingItems(JComponent f) {
|
|
Container desktop = f.getParent();
|
|
Component[] children = desktop.getComponents();
|
|
int i = 0;
|
|
for (i = 0; i < children.length; i++) {
|
|
if (children[i] == f) {
|
|
break;
|
|
}
|
|
}
|
|
// System.out.println(i);
|
|
Rectangle[] floaters = new Rectangle[i];
|
|
for (i = 0; i < floaters.length; i++) {
|
|
floaters[i] = children[i].getBounds();
|
|
}
|
|
|
|
return floaters;
|
|
}
|
|
|
|
/**
|
|
* This method is here to clean up problems associated
|
|
* with a race condition which can occur when the full contents
|
|
* of a copyArea's source argument is not available onscreen.
|
|
* This uses brute force to clean up in case of possible damage
|
|
*/
|
|
private void emergencyCleanup(final JComponent f) {
|
|
|
|
if ( ((JInternalFrame)f).danger ) {
|
|
|
|
SwingUtilities.invokeLater( new Runnable(){
|
|
public void run(){
|
|
|
|
((JInternalFrame)f).isDragging = false;
|
|
f.paintImmediately(0,0,
|
|
f.getWidth(),
|
|
f.getHeight());
|
|
|
|
//finalFrame.repaint();
|
|
((JInternalFrame)f).isDragging = true;
|
|
// System.out.println("repair complete");
|
|
}});
|
|
|
|
((JInternalFrame)f).danger = false;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|