| /* | |
| * Copyright (c) 1997, 2024, 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.Serial; | |
| import java.io.Serializable; | |
| import java.util.EventListener; | |
| import sun.awt.AWTAccessor; | |
| import sun.awt.AWTAccessor.DragSourceContextAccessor; | |
| import sun.awt.dnd.SunDragSourceContextPeer; | |
| /** | |
| * 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: | |
| * <UL> | |
| * <LI>1 default instance per JVM for the lifetime of that JVM. | |
| * <LI>1 instance per class of potential Drag Initiator object (e.g | |
| * TextField). [implementation dependent] | |
| * <LI>1 per instance of a particular | |
| * {@code Component}, or application specific | |
| * object associated with a {@code Component} | |
| * instance in the GUI. [implementation dependent] | |
| * <LI>Some other arbitrary association. [implementation dependent] | |
| *</UL> | |
| * | |
| * Once the {@code DragSource} is | |
| * obtained, a {@code DragGestureRecognizer} should | |
| * also be obtained to associate the {@code DragSource} | |
| * with a particular | |
| * {@code Component}. | |
| * <P> | |
| * 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}. | |
| *<P> | |
| * 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. | |
| * <P> | |
| * The startDrag() method invokes the | |
| * createDragSourceContext() method to | |
| * instantiate an appropriate | |
| * {@code DragSourceContext} | |
| * and associate the {@code DragSourceContextPeer} | |
| * with that. | |
| * <P> | |
| * 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. | |
| * <P> | |
| * 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 { | |
| /** | |
| * Use serialVersionUID from JDK 1.4 for interoperability. | |
| */ | |
| @Serial | |
| 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 | |
| * @throws 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 {@code true} if the Drag Image support is available on this | |
| * platform, otherwise {@code false} | |
| */ | |
| 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}. | |
| * | |
| * @throws 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 <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> | |
| * 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 <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> | |
| * 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 <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> | |
| * 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 <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> 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. | |
| * <p> | |
| * To incorporate a new {@code DragSourceContext} | |
| * subclass, subclass {@code DragSource} and | |
| * override this method. | |
| * <p> | |
| * 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. | |
| * <p> | |
| * 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 <a href="DragSourceContext.html#defaultCursor">DragSourceContext</a> 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 <T> the type of {@code DragGestureRecognizer} to create | |
| * @param recognizerAbstractClass the requested abstract type | |
| * @param c the {@code Component} target | |
| * @param actions the permitted source drag actions | |
| * @param dgl the {@code DragGestureListener} to notify | |
| * | |
| * @return the new {@code DragGestureRecognizer} or {@code null} | |
| * if the {@code Toolkit.createDragGestureRecognizer} method | |
| * has no implementation available for | |
| * the requested {@code DragGestureRecognizer} | |
| * subclass and returns {@code null} | |
| */ | |
| public <T extends DragGestureRecognizer> T | |
| createDragGestureRecognizer(Class<T> recognizerAbstractClass, | |
| Component c, int actions, | |
| DragGestureListener dgl) | |
| { | |
| return Toolkit.getDefaultToolkit().createDragGestureRecognizer(recognizerAbstractClass, this, c, actions, dgl); | |
| } | |
| /** | |
| * Creates a new {@code DragGestureRecognizer} | |
| * that implements the default | |
| * abstract subclass of {@code DragGestureRecognizer} | |
| * for this {@code DragSource}, | |
| * and sets the specified {@code Component} | |
| * and {@code DragGestureListener} on the | |
| * newly created object. | |
| * | |
| * For this {@code DragSource} | |
| * the default is {@code MouseDragGestureRecognizer}. | |
| * | |
| * @param c the {@code Component} target for the recognizer | |
| * @param actions the permitted source actions | |
| * @param dgl the {@code DragGestureListener} to notify | |
| * | |
| * @return the new {@code DragGestureRecognizer} or {@code null} | |
| * if the {@code Toolkit.createDragGestureRecognizer} method | |
| * has no implementation available for | |
| * the requested {@code DragGestureRecognizer} | |
| * subclass and returns {@code null} | |
| */ | |
| public DragGestureRecognizer createDefaultDragGestureRecognizer(Component c, int actions, DragGestureListener dgl) { | |
| return Toolkit.getDefaultToolkit().createDragGestureRecognizer(MouseDragGestureRecognizer.class, this, c, actions, dgl); | |
| } | |
| /** | |
| * Adds the specified {@code DragSourceListener} to this | |
| * {@code DragSource} to receive drag source events during drag | |
| * operations initiated with this {@code DragSource}. | |
| * If a {@code null} listener is specified, no action is taken and no | |
| * exception is thrown. | |
| * | |
| * @param dsl the {@code DragSourceListener} to add | |
| * | |
| * @see #removeDragSourceListener | |
| * @see #getDragSourceListeners | |
| * @since 1.4 | |
| */ | |
| public void addDragSourceListener(DragSourceListener dsl) { | |
| if (dsl != null) { | |
| synchronized (this) { | |
| listener = DnDEventMulticaster.add(listener, dsl); | |
| } | |
| } | |
| } | |
| /** | |
| * Removes the specified {@code DragSourceListener} from this | |
| * {@code DragSource}. | |
| * If a {@code null} listener is specified, no action is taken and no | |
| * exception is thrown. | |
| * If the listener specified by the argument was not previously added to | |
| * this {@code DragSource}, no action is taken and no exception | |
| * is thrown. | |
| * | |
| * @param dsl the {@code DragSourceListener} to remove | |
| * | |
| * @see #addDragSourceListener | |
| * @see #getDragSourceListeners | |
| * @since 1.4 | |
| */ | |
| public void removeDragSourceListener(DragSourceListener dsl) { | |
| if (dsl != null) { | |
| synchronized (this) { | |
| listener = DnDEventMulticaster.remove(listener, dsl); | |
| } | |
| } | |
| } | |
| /** | |
| * Gets all the {@code DragSourceListener}s | |
| * registered with this {@code DragSource}. | |
| * | |
| * @return all of this {@code DragSource}'s | |
| * {@code DragSourceListener}s or an empty array if no | |
| * such listeners are currently registered | |
| * | |
| * @see #addDragSourceListener | |
| * @see #removeDragSourceListener | |
| * @since 1.4 | |
| */ | |
| public DragSourceListener[] getDragSourceListeners() { | |
| return getListeners(DragSourceListener.class); | |
| } | |
| /** | |
| * Adds the specified {@code DragSourceMotionListener} to this | |
| * {@code DragSource} to receive drag motion events during drag | |
| * operations initiated with this {@code DragSource}. | |
| * If a {@code null} listener is specified, no action is taken and no | |
| * exception is thrown. | |
| * | |
| * @param dsml the {@code DragSourceMotionListener} to add | |
| * | |
| * @see #removeDragSourceMotionListener | |
| * @see #getDragSourceMotionListeners | |
| * @since 1.4 | |
| */ | |
| public void addDragSourceMotionListener(DragSourceMotionListener dsml) { | |
| if (dsml != null) { | |
| synchronized (this) { | |
| motionListener = DnDEventMulticaster.add(motionListener, dsml); | |
| } | |
| } | |
| } | |
| /** | |
| * Removes the specified {@code DragSourceMotionListener} from this | |
| * {@code DragSource}. | |
| * If a {@code null} listener is specified, no action is taken and no | |
| * exception is thrown. | |
| * If the listener specified by the argument was not previously added to | |
| * this {@code DragSource}, no action is taken and no exception | |
| * is thrown. | |
| * | |
| * @param dsml the {@code DragSourceMotionListener} to remove | |
| * | |
| * @see #addDragSourceMotionListener | |
| * @see #getDragSourceMotionListeners | |
| * @since 1.4 | |
| */ | |
| public void removeDragSourceMotionListener(DragSourceMotionListener dsml) { | |
| if (dsml != null) { | |
| synchronized (this) { | |
| motionListener = DnDEventMulticaster.remove(motionListener, dsml); | |
| } | |
| } | |
| } | |
| /** | |
| * Gets all of the {@code DragSourceMotionListener}s | |
| * registered with this {@code DragSource}. | |
| * | |
| * @return all of this {@code DragSource}'s | |
| * {@code DragSourceMotionListener}s or an empty array if no | |
| * such listeners are currently registered | |
| * | |
| * @see #addDragSourceMotionListener | |
| * @see #removeDragSourceMotionListener | |
| * @since 1.4 | |
| */ | |
| public DragSourceMotionListener[] getDragSourceMotionListeners() { | |
| return getListeners(DragSourceMotionListener.class); | |
| } | |
| /** | |
| * Gets all the objects currently registered as | |
| * <code><em>Foo</em>Listener</code>s upon this {@code DragSource}. | |
| * <code><em>Foo</em>Listener</code>s are registered using the | |
| * <code>add<em>Foo</em>Listener</code> method. | |
| * | |
| * @param <T> the type of listener objects | |
| * @param listenerType the type of listeners requested; this parameter | |
| * should specify an interface that descends from | |
| * {@code java.util.EventListener} | |
| * @return an array of all objects registered as | |
| * <code><em>Foo</em>Listener</code>s on this | |
| * {@code DragSource}, or an empty array if no such listeners | |
| * have been added | |
| * @throws 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 <T extends EventListener> T[] getListeners(Class<T> listenerType) { | |
| EventListener l = null; | |
| if (listenerType == DragSourceListener.class) { | |
| l = listener; | |
| } else if (listenerType == DragSourceMotionListener.class) { | |
| l = motionListener; | |
| } | |
| return DnDEventMulticaster.getListeners(l, listenerType); | |
| } | |
| /** | |
| * This method calls {@code dragEnter} on the | |
| * {@code DragSourceListener}s registered with this | |
| * {@code DragSource}, and passes them the specified | |
| * {@code DragSourceDragEvent}. | |
| * | |
| * @param dsde the {@code DragSourceDragEvent} | |
| */ | |
| void processDragEnter(DragSourceDragEvent dsde) { | |
| DragSourceListener dsl = listener; | |
| if (dsl != null) { | |
| dsl.dragEnter(dsde); | |
| } | |
| } | |
| /** | |
| * This method calls {@code dragOver} on the | |
| * {@code DragSourceListener}s registered with this | |
| * {@code DragSource}, and passes them the specified | |
| * {@code DragSourceDragEvent}. | |
| * | |
| * @param dsde the {@code DragSourceDragEvent} | |
| */ | |
| void processDragOver(DragSourceDragEvent dsde) { | |
| DragSourceListener dsl = listener; | |
| if (dsl != null) { | |
| dsl.dragOver(dsde); | |
| } | |
| } | |
| /** | |
| * This method calls {@code dropActionChanged} on the | |
| * {@code DragSourceListener}s registered with this | |
| * {@code DragSource}, and passes them the specified | |
| * {@code DragSourceDragEvent}. | |
| * | |
| * @param dsde the {@code DragSourceDragEvent} | |
| */ | |
| void processDropActionChanged(DragSourceDragEvent dsde) { | |
| DragSourceListener dsl = listener; | |
| if (dsl != null) { | |
| dsl.dropActionChanged(dsde); | |
| } | |
| } | |
| /** | |
| * This method calls {@code dragExit} on the | |
| * {@code DragSourceListener}s registered with this | |
| * {@code DragSource}, and passes them the specified | |
| * {@code DragSourceEvent}. | |
| * | |
| * @param dse the {@code DragSourceEvent} | |
| */ | |
| void processDragExit(DragSourceEvent dse) { | |
| DragSourceListener dsl = listener; | |
| if (dsl != null) { | |
| dsl.dragExit(dse); | |
| } | |
| } | |
| /** | |
| * This method calls {@code dragDropEnd} on the | |
| * {@code DragSourceListener}s registered with this | |
| * {@code DragSource}, and passes them the specified | |
| * {@code DragSourceDropEvent}. | |
| * | |
| * @param dsde the {@code DragSourceEvent} | |
| */ | |
| void processDragDropEnd(DragSourceDropEvent dsde) { | |
| DragSourceListener dsl = listener; | |
| if (dsl != null) { | |
| dsl.dragDropEnd(dsde); | |
| } | |
| } | |
| /** | |
| * This method calls {@code dragMouseMoved} on the | |
| * {@code DragSourceMotionListener}s registered with this | |
| * {@code DragSource}, and passes them the specified | |
| * {@code DragSourceDragEvent}. | |
| * | |
| * @param dsde the {@code DragSourceEvent} | |
| */ | |
| void processDragMouseMoved(DragSourceDragEvent dsde) { | |
| DragSourceMotionListener dsml = motionListener; | |
| if (dsml != null) { | |
| dsml.dragMouseMoved(dsde); | |
| } | |
| } | |
| /** | |
| * Serializes this {@code DragSource}. This method first performs | |
| * default serialization. Next, it writes out this object's | |
| * {@code FlavorMap} if and only if it can be serialized. If not, | |
| * {@code null} is written instead. Next, it writes out | |
| * {@code Serializable} listeners registered with this | |
| * object. Listeners are written in 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: | |
| * <ul> | |
| * <li>{@code dragSourceListenerK} indicating a | |
| * {@code DragSourceListener} object; | |
| * <li>{@code dragSourceMotionListenerK} indicating a | |
| * {@code DragSourceMotionListener} object. | |
| * </ul> | |
| * | |
| * @param s the {@code ObjectOutputStream} to write | |
| * @throws IOException if an I/O error occurs | |
| * @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: | |
| * <ul> | |
| * <li>{@code dragSourceListenerK} indicating a | |
| * {@code DragSourceListener} object; | |
| * <li>{@code dragSourceMotionListenerK} indicating a | |
| * {@code DragSourceMotionListener} object. | |
| * </ul>. | |
| * @since 1.4 | |
| */ | |
| @Serial | |
| 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: | |
| * <ul> | |
| * <li>If a key object is a {@code String} equal to | |
| * {@code dragSourceListenerK}, a {@code DragSourceListener} is | |
| * deserialized using the corresponding value object and added to this | |
| * {@code DragSource}. | |
| * <li>If a key object is a {@code String} equal to | |
| * {@code dragSourceMotionListenerK}, a | |
| * {@code DragSourceMotionListener} is deserialized using the | |
| * corresponding value object and added to this {@code DragSource}. | |
| * <li>Otherwise, the key/value pair is skipped. | |
| * </ul> | |
| * | |
| * @param s the {@code ObjectInputStream} to read | |
| * @throws ClassNotFoundException if the class of a serialized object could | |
| * not be found | |
| * @throws IOException if an I/O error occurs | |
| * @see java.awt.datatransfer.SystemFlavorMap#getDefaultFlavorMap | |
| * @since 1.4 | |
| */ | |
| @Serial | |
| 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. | |
| * <p> | |
| * 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 = Integer.getInteger("awt.dnd.drag.threshold", 0); | |
| 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; | |
| } |