/* * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.awt.dnd; import java.awt.Component; import java.awt.Cursor; import java.awt.GraphicsEnvironment; import java.awt.HeadlessException; import java.awt.Image; import java.awt.Point; import java.awt.Toolkit; import java.awt.datatransfer.FlavorMap; import java.awt.datatransfer.SystemFlavorMap; import java.awt.datatransfer.Transferable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.security.AccessController; import java.util.EventListener; import sun.awt.AWTAccessor; import sun.awt.AWTAccessor.DragSourceContextAccessor; import sun.awt.dnd.SunDragSourceContextPeer; import sun.security.action.GetIntegerAction; /** * The {@code DragSource} is the entity responsible * for the initiation of the Drag * and Drop operation, and may be used in a number of scenarios: *
* The initial interpretation of the user's gesture, * and the subsequent starting of the drag operation * are the responsibility of the implementing * {@code Component}, which is usually * implemented by a {@code DragGestureRecognizer}. *
* When a drag gesture occurs, the * {@code DragSource}'s * startDrag() method shall be * invoked in order to cause processing * of the user's navigational * gestures and delivery of Drag and Drop * protocol notifications. A * {@code DragSource} shall only * permit a single Drag and Drop operation to be * current at any one time, and shall * reject any further startDrag() requests * by throwing an {@code IllegalDnDOperationException} * until such time as the extant operation is complete. *
* The startDrag() method invokes the * createDragSourceContext() method to * instantiate an appropriate * {@code DragSourceContext} * and associate the {@code DragSourceContextPeer} * with that. *
* If the Drag and Drop System is * unable to initiate a drag operation for * some reason, the startDrag() method throws * a {@code java.awt.dnd.InvalidDnDOperationException} * to signal such a condition. Typically this * exception is thrown when the underlying platform * system is either not in a state to * initiate a drag, or the parameters specified are invalid. *
* Note that during the drag, the * set of operations exposed by the source * at the start of the drag operation may not change * until the operation is complete. * The operation(s) are constant for the * duration of the operation with respect to the * {@code DragSource}. * * @since 1.2 */ public class DragSource implements Serializable { private static final long serialVersionUID = 6236096958971414066L; /* * load a system default cursor */ private static Cursor load(String name) { if (GraphicsEnvironment.isHeadless()) { return null; } try { return (Cursor)Toolkit.getDefaultToolkit().getDesktopProperty(name); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("failed to load system cursor: " + name + " : " + e.getMessage()); } } /** * The default {@code Cursor} to use with a copy operation indicating * that a drop is currently allowed. {@code null} if * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. * * @see java.awt.GraphicsEnvironment#isHeadless */ public static final Cursor DefaultCopyDrop = load("DnD.Cursor.CopyDrop"); /** * The default {@code Cursor} to use with a move operation indicating * that a drop is currently allowed. {@code null} if * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. * * @see java.awt.GraphicsEnvironment#isHeadless */ public static final Cursor DefaultMoveDrop = load("DnD.Cursor.MoveDrop"); /** * The default {@code Cursor} to use with a link operation indicating * that a drop is currently allowed. {@code null} if * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. * * @see java.awt.GraphicsEnvironment#isHeadless */ public static final Cursor DefaultLinkDrop = load("DnD.Cursor.LinkDrop"); /** * The default {@code Cursor} to use with a copy operation indicating * that a drop is currently not allowed. {@code null} if * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. * * @see java.awt.GraphicsEnvironment#isHeadless */ public static final Cursor DefaultCopyNoDrop = load("DnD.Cursor.CopyNoDrop"); /** * The default {@code Cursor} to use with a move operation indicating * that a drop is currently not allowed. {@code null} if * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. * * @see java.awt.GraphicsEnvironment#isHeadless */ public static final Cursor DefaultMoveNoDrop = load("DnD.Cursor.MoveNoDrop"); /** * The default {@code Cursor} to use with a link operation indicating * that a drop is currently not allowed. {@code null} if * {@code GraphicsEnvironment.isHeadless()} returns {@code true}. * * @see java.awt.GraphicsEnvironment#isHeadless */ public static final Cursor DefaultLinkNoDrop = load("DnD.Cursor.LinkNoDrop"); private static final DragSource dflt = (GraphicsEnvironment.isHeadless()) ? null : new DragSource(); /** * Internal constants for serialization. */ static final String dragSourceListenerK = "dragSourceL"; static final String dragSourceMotionListenerK = "dragSourceMotionL"; /** * Gets the {@code DragSource} object associated with * the underlying platform. * * @return the platform DragSource * @exception HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ public static DragSource getDefaultDragSource() { if (GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } else { return dflt; } } /** * Reports * whether or not drag * {@code Image} support * is available on the underlying platform. * * @return if the Drag Image support is available on this platform */ public static boolean isDragImageSupported() { Toolkit t = Toolkit.getDefaultToolkit(); Boolean supported; try { supported = (Boolean)Toolkit.getDefaultToolkit().getDesktopProperty("DnD.isDragImageSupported"); return supported.booleanValue(); } catch (Exception e) { return false; } } /** * Creates a new {@code DragSource}. * * @exception HeadlessException if GraphicsEnvironment.isHeadless() * returns true * @see java.awt.GraphicsEnvironment#isHeadless */ public DragSource() throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { throw new HeadlessException(); } } /** * Start a drag, given the {@code DragGestureEvent} * that initiated the drag, the initial * {@code Cursor} to use, * the {@code Image} to drag, * the offset of the {@code Image} origin * from the hotspot of the {@code Cursor} at * the instant of the trigger, * the {@code Transferable} subject data * of the drag, the {@code DragSourceListener}, * and the {@code FlavorMap}. * * @param trigger the {@code DragGestureEvent} that initiated the drag * @param dragCursor the initial {@code Cursor} for this drag operation * or {@code null} for the default cursor handling; * see DragSourceContext * for more details on the cursor handling mechanism during drag and drop * @param dragImage the image to drag or {@code null} * @param imageOffset the offset of the {@code Image} origin from the hotspot * of the {@code Cursor} at the instant of the trigger * @param transferable the subject data of the drag * @param dsl the {@code DragSourceListener} * @param flavorMap the {@code FlavorMap} to use, or {@code null} * * @throws java.awt.dnd.InvalidDnDOperationException * if the Drag and Drop * system is unable to initiate a drag operation, or if the user * attempts to start a drag while an existing drag operation * is still executing */ public void startDrag(DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point imageOffset, Transferable transferable, DragSourceListener dsl, FlavorMap flavorMap) throws InvalidDnDOperationException { SunDragSourceContextPeer.setDragDropInProgress(true); try { if (flavorMap != null) this.flavorMap = flavorMap; DragSourceContext dsc = createDragSourceContext(trigger, dragCursor, dragImage, imageOffset, transferable, dsl); if (dsc == null) { throw new InvalidDnDOperationException(); } DragSourceContextAccessor acc = AWTAccessor.getDragSourceContextAccessor(); acc.getPeer(dsc).startDrag(dsc, dsc.getCursor(), dragImage, imageOffset); // may throw } catch (RuntimeException e) { SunDragSourceContextPeer.setDragDropInProgress(false); throw e; } } /** * Start a drag, given the {@code DragGestureEvent} * that initiated the drag, the initial * {@code Cursor} to use, * the {@code Transferable} subject data * of the drag, the {@code DragSourceListener}, * and the {@code FlavorMap}. * * @param trigger the {@code DragGestureEvent} that * initiated the drag * @param dragCursor the initial {@code Cursor} for this drag operation * or {@code null} for the default cursor handling; * see DragSourceContext * for more details on the cursor handling mechanism during drag and drop * @param transferable the subject data of the drag * @param dsl the {@code DragSourceListener} * @param flavorMap the {@code FlavorMap} to use or {@code null} * * @throws java.awt.dnd.InvalidDnDOperationException * if the Drag and Drop * system is unable to initiate a drag operation, or if the user * attempts to start a drag while an existing drag operation * is still executing */ public void startDrag(DragGestureEvent trigger, Cursor dragCursor, Transferable transferable, DragSourceListener dsl, FlavorMap flavorMap) throws InvalidDnDOperationException { startDrag(trigger, dragCursor, null, null, transferable, dsl, flavorMap); } /** * Start a drag, given the {@code DragGestureEvent} * that initiated the drag, the initial {@code Cursor} * to use, * the {@code Image} to drag, * the offset of the {@code Image} origin * from the hotspot of the {@code Cursor} * at the instant of the trigger, * the subject data of the drag, and * the {@code DragSourceListener}. * * @param trigger the {@code DragGestureEvent} that initiated the drag * @param dragCursor the initial {@code Cursor} for this drag operation * or {@code null} for the default cursor handling; * see DragSourceContext * for more details on the cursor handling mechanism during drag and drop * @param dragImage the {@code Image} to drag or {@code null} * @param dragOffset the offset of the {@code Image} origin from the hotspot * of the {@code Cursor} at the instant of the trigger * @param transferable the subject data of the drag * @param dsl the {@code DragSourceListener} * * @throws java.awt.dnd.InvalidDnDOperationException * if the Drag and Drop * system is unable to initiate a drag operation, or if the user * attempts to start a drag while an existing drag operation * is still executing */ public void startDrag(DragGestureEvent trigger, Cursor dragCursor, Image dragImage, Point dragOffset, Transferable transferable, DragSourceListener dsl) throws InvalidDnDOperationException { startDrag(trigger, dragCursor, dragImage, dragOffset, transferable, dsl, null); } /** * Start a drag, given the {@code DragGestureEvent} * that initiated the drag, the initial * {@code Cursor} to * use, * the {@code Transferable} subject data * of the drag, and the {@code DragSourceListener}. * * @param trigger the {@code DragGestureEvent} that initiated the drag * @param dragCursor the initial {@code Cursor} for this drag operation * or {@code null} for the default cursor handling; * see DragSourceContext class * for more details on the cursor handling mechanism during drag and drop * @param transferable the subject data of the drag * @param dsl the {@code DragSourceListener} * * @throws java.awt.dnd.InvalidDnDOperationException * if the Drag and Drop * system is unable to initiate a drag operation, or if the user * attempts to start a drag while an existing drag operation * is still executing */ public void startDrag(DragGestureEvent trigger, Cursor dragCursor, Transferable transferable, DragSourceListener dsl) throws InvalidDnDOperationException { startDrag(trigger, dragCursor, null, null, transferable, dsl, null); } /** * Creates the {@code DragSourceContext} to handle the current drag * operation. *
* To incorporate a new {@code DragSourceContext} * subclass, subclass {@code DragSource} and * override this method. *
* If {@code dragImage} is {@code null}, no image is used * to represent the drag over feedback for this drag operation, but * {@code NullPointerException} is not thrown. *
* If {@code dsl} is {@code null}, no drag source listener
* is registered with the created {@code DragSourceContext},
* but {@code NullPointerException} is not thrown.
*
* @param dgl The {@code DragGestureEvent} that triggered the
* drag
* @param dragCursor The initial {@code Cursor} for this drag operation
* or {@code null} for the default cursor handling;
* see DragSourceContext class
* for more details on the cursor handling mechanism during drag and drop
* @param dragImage The {@code Image} to drag or {@code null}
* @param imageOffset The offset of the {@code Image} origin from the
* hotspot of the cursor at the instant of the trigger
* @param t The subject data of the drag
* @param dsl The {@code DragSourceListener}
*
* @return the {@code DragSourceContext}
*
* @throws NullPointerException if {@code dscp} is {@code null}
* @throws NullPointerException if {@code dgl} is {@code null}
* @throws NullPointerException if {@code dragImage} is not
* {@code null} and {@code imageOffset} is {@code null}
* @throws NullPointerException if {@code t} is {@code null}
* @throws IllegalArgumentException if the {@code Component}
* associated with the trigger event is {@code null}.
* @throws IllegalArgumentException if the {@code DragSource} for the
* trigger event is {@code null}.
* @throws IllegalArgumentException if the drag action for the
* trigger event is {@code DnDConstants.ACTION_NONE}.
* @throws IllegalArgumentException if the source actions for the
* {@code DragGestureRecognizer} associated with the trigger
* event are equal to {@code DnDConstants.ACTION_NONE}.
*/
protected DragSourceContext createDragSourceContext(DragGestureEvent dgl,
Cursor dragCursor,
Image dragImage,
Point imageOffset,
Transferable t,
DragSourceListener dsl) {
return new DragSourceContext(dgl, dragCursor, dragImage, imageOffset, t, dsl);
}
/**
* This method returns the
* {@code FlavorMap} for this {@code DragSource}.
*
* @return the {@code FlavorMap} for this {@code DragSource}
*/
public FlavorMap getFlavorMap() { return flavorMap; }
/**
* Creates a new {@code DragGestureRecognizer}
* that implements the specified
* abstract subclass of
* {@code DragGestureRecognizer}, and
* sets the specified {@code Component}
* and {@code DragGestureListener} on
* the newly created object.
*
* @param
* If the system property {@code awt.dnd.drag.threshold} is set to
* a positive integer, this method returns the value of the system property;
* otherwise if a pertinent desktop property is available and supported by
* the implementation of the Java platform, this method returns the value of
* that property; otherwise this method returns some default value.
* The pertinent desktop property can be queried using
* {@code java.awt.Toolkit.getDesktopProperty("DnD.gestureMotionThreshold")}.
*
* @return the drag gesture motion threshold
* @see MouseDragGestureRecognizer
* @since 1.5
*/
public static int getDragThreshold() {
int ts = AccessController.doPrivileged(
new GetIntegerAction("awt.dnd.drag.threshold", 0)).intValue();
if (ts > 0) {
return ts;
} else {
Integer td = (Integer)Toolkit.getDefaultToolkit().
getDesktopProperty("DnD.gestureMotionThreshold");
if (td != null) {
return td.intValue();
}
}
return 5;
}
/*
* fields
*/
private transient FlavorMap flavorMap = SystemFlavorMap.getDefaultFlavorMap();
private transient DragSourceListener listener;
private transient DragSourceMotionListener motionListener;
}
FooListener
s upon this {@code DragSource}.
* FooListener
s are registered using the
* addFooListener
method.
*
* @param FooListener
s on this
* {@code DragSource}, or an empty array if no such listeners
* have been added
* @exception ClassCastException if {@code listenerType}
* doesn't specify a class or interface that implements
* {@code java.util.EventListener}
*
* @see #getDragSourceListeners
* @see #getDragSourceMotionListeners
* @since 1.4
*/
public
*
*
* @serialData Either a {@code FlavorMap} instance, or
* {@code null}, followed by a {@code null}-terminated
* sequence of 0 or more pairs; the pair consists of a
* {@code String} and an {@code Object}; the
* {@code String} indicates the type of the {@code Object}
* and is one of the following:
*
*
.
* @since 1.4
*/
private void writeObject(ObjectOutputStream s) throws IOException {
s.defaultWriteObject();
s.writeObject(SerializationTester.test(flavorMap) ? flavorMap : null);
DnDEventMulticaster.save(s, dragSourceListenerK, listener);
DnDEventMulticaster.save(s, dragSourceMotionListenerK, motionListener);
s.writeObject(null);
}
/**
* Deserializes this {@code DragSource}. This method first performs
* default deserialization. Next, this object's {@code FlavorMap} is
* deserialized by using the next object in the stream.
* If the resulting {@code FlavorMap} is {@code null}, this
* object's {@code FlavorMap} is set to the default FlavorMap for
* this thread's {@code ClassLoader}.
* Next, this object's listeners are deserialized by reading a
* {@code null}-terminated sequence of 0 or more key/value pairs
* from the stream:
*
*
*
* @see java.awt.datatransfer.SystemFlavorMap#getDefaultFlavorMap
* @since 1.4
*/
private void readObject(ObjectInputStream s)
throws ClassNotFoundException, IOException {
s.defaultReadObject();
// 'flavorMap' was written explicitly
flavorMap = (FlavorMap)s.readObject();
// Implementation assumes 'flavorMap' is never null.
if (flavorMap == null) {
flavorMap = SystemFlavorMap.getDefaultFlavorMap();
}
Object keyOrNull;
while (null != (keyOrNull = s.readObject())) {
String key = ((String)keyOrNull).intern();
if (dragSourceListenerK == key) {
addDragSourceListener((DragSourceListener)(s.readObject()));
} else if (dragSourceMotionListenerK == key) {
addDragSourceMotionListener(
(DragSourceMotionListener)(s.readObject()));
} else {
// skip value for unrecognized key
s.readObject();
}
}
}
/**
* Returns the drag gesture motion threshold. The drag gesture motion threshold
* defines the recommended behavior for {@link MouseDragGestureRecognizer}s.
*