| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package sun.awt.dnd;  | 
 | 
 | 
 | 
import java.awt.AWTEvent;  | 
 | 
import java.awt.Component;  | 
 | 
import java.awt.Cursor;  | 
 | 
import java.awt.EventQueue;  | 
 | 
import java.awt.Image;  | 
 | 
import java.awt.Point;  | 
 | 
 | 
 | 
import java.awt.datatransfer.Transferable;  | 
 | 
 | 
 | 
import java.awt.dnd.DnDConstants;  | 
 | 
import java.awt.dnd.DragSourceContext;  | 
 | 
import java.awt.dnd.DragSourceEvent;  | 
 | 
import java.awt.dnd.DragSourceDropEvent;  | 
 | 
import java.awt.dnd.DragSourceDragEvent;  | 
 | 
import java.awt.dnd.DragGestureEvent;  | 
 | 
import java.awt.dnd.InvalidDnDOperationException;  | 
 | 
 | 
 | 
import java.awt.dnd.peer.DragSourceContextPeer;  | 
 | 
 | 
 | 
import java.awt.event.InputEvent;  | 
 | 
import java.awt.event.MouseEvent;  | 
 | 
 | 
 | 
import java.util.Map;  | 
 | 
import java.util.SortedMap;  | 
 | 
 | 
 | 
import sun.awt.SunToolkit;  | 
 | 
import sun.awt.datatransfer.DataTransferer;  | 
 | 
import java.awt.datatransfer.DataFlavor;  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
public abstract class SunDragSourceContextPeer implements DragSourceContextPeer { | 
 | 
 | 
 | 
    private DragGestureEvent  trigger;  | 
 | 
    private Component         component;  | 
 | 
    private Cursor            cursor;  | 
 | 
    private Image             dragImage;  | 
 | 
    private Point             dragImageOffset;  | 
 | 
    private long              nativeCtxt;  | 
 | 
    private DragSourceContext dragSourceContext;  | 
 | 
    private int               sourceActions;  | 
 | 
 | 
 | 
    private static boolean    dragDropInProgress = false;  | 
 | 
    private static boolean    discardingMouseEvents = false;  | 
 | 
 | 
 | 
    /*  | 
 | 
     * dispatch constants  | 
 | 
     */  | 
 | 
 | 
 | 
    protected final static int DISPATCH_ENTER   = 1;  | 
 | 
    protected final static int DISPATCH_MOTION  = 2;  | 
 | 
    protected final static int DISPATCH_CHANGED = 3;  | 
 | 
    protected final static int DISPATCH_EXIT    = 4;  | 
 | 
    protected final static int DISPATCH_FINISH  = 5;  | 
 | 
    protected final static int DISPATCH_MOUSE_MOVED  = 6;  | 
 | 
 | 
 | 
    /**  | 
 | 
     * construct a new SunDragSourceContextPeer  | 
 | 
     */  | 
 | 
 | 
 | 
    public SunDragSourceContextPeer(DragGestureEvent dge) { | 
 | 
        trigger = dge;  | 
 | 
        if (trigger != null) { | 
 | 
            component = trigger.getComponent();  | 
 | 
        } else { | 
 | 
            component = null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public void startSecondaryEventLoop(){} | 
 | 
    public void quitSecondaryEventLoop(){} | 
 | 
 | 
 | 
    /**  | 
 | 
     * initiate a DnD operation ...  | 
 | 
     */  | 
 | 
 | 
 | 
    public void startDrag(DragSourceContext dsc, Cursor c, Image di, Point p)  | 
 | 
      throws InvalidDnDOperationException { | 
 | 
 | 
 | 
          | 
 | 
         * DragGestureRecognizer is empty */  | 
 | 
        if (getTrigger().getTriggerEvent() == null) { | 
 | 
            throw new InvalidDnDOperationException("DragGestureEvent has a null trigger"); | 
 | 
        }  | 
 | 
 | 
 | 
        dragSourceContext = dsc;  | 
 | 
        cursor            = c;  | 
 | 
        sourceActions     = getDragSourceContext().getSourceActions();  | 
 | 
        dragImage         = di;  | 
 | 
        dragImageOffset   = p;  | 
 | 
 | 
 | 
        Transferable transferable  = getDragSourceContext().getTransferable();  | 
 | 
        SortedMap<Long,DataFlavor> formatMap = DataTransferer.getInstance().  | 
 | 
            getFormatsForTransferable(transferable, DataTransferer.adaptFlavorMap  | 
 | 
                (getTrigger().getDragSource().getFlavorMap()));  | 
 | 
        long[] formats = DataTransferer.getInstance().  | 
 | 
            keysToLongArray(formatMap);  | 
 | 
        startDrag(transferable, formats, formatMap);  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        discardingMouseEvents = true;  | 
 | 
        EventQueue.invokeLater(new Runnable() { | 
 | 
                public void run() { | 
 | 
                    discardingMouseEvents = false;  | 
 | 
                }  | 
 | 
            });  | 
 | 
    }  | 
 | 
 | 
 | 
    protected abstract void startDrag(Transferable trans,  | 
 | 
                                      long[] formats, Map formatMap);  | 
 | 
 | 
 | 
    /**  | 
 | 
     * set cursor  | 
 | 
     */  | 
 | 
 | 
 | 
    public void setCursor(Cursor c) throws InvalidDnDOperationException { | 
 | 
        synchronized (this) { | 
 | 
            if (cursor == null || !cursor.equals(c)) { | 
 | 
                cursor = c;  | 
 | 
                // NOTE: native context can be null at this point.  | 
 | 
                  | 
 | 
                setNativeCursor(getNativeContext(), c,  | 
 | 
                                c != null ? c.getType() : 0);  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * return cursor  | 
 | 
     */  | 
 | 
 | 
 | 
    public Cursor getCursor() { | 
 | 
        return cursor;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Image getDragImage() { | 
 | 
        return dragImage;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Point getDragImageOffset() { | 
 | 
        if (dragImageOffset == null) { | 
 | 
            return new Point(0,0);  | 
 | 
        }  | 
 | 
        return new Point(dragImageOffset);  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * downcall into native code  | 
 | 
     */  | 
 | 
 | 
 | 
 | 
 | 
    protected abstract void setNativeCursor(long nativeCtxt, Cursor c,  | 
 | 
                                            int cType);  | 
 | 
 | 
 | 
    protected synchronized void setTrigger(DragGestureEvent dge) { | 
 | 
        trigger = dge;  | 
 | 
        if (trigger != null) { | 
 | 
            component = trigger.getComponent();  | 
 | 
        } else { | 
 | 
            component = null;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    protected DragGestureEvent getTrigger() { | 
 | 
        return trigger;  | 
 | 
    }  | 
 | 
 | 
 | 
    protected Component getComponent() { | 
 | 
        return component;  | 
 | 
    }  | 
 | 
 | 
 | 
    protected synchronized void setNativeContext(long ctxt) { | 
 | 
        nativeCtxt = ctxt;  | 
 | 
    }  | 
 | 
 | 
 | 
    protected synchronized long getNativeContext() { | 
 | 
        return nativeCtxt;  | 
 | 
    }  | 
 | 
 | 
 | 
    protected DragSourceContext getDragSourceContext() { | 
 | 
        return dragSourceContext;  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * Notify the peer that the transferables' DataFlavors have changed.  | 
 | 
     *  | 
 | 
     * No longer useful as the transferables are determined at the time  | 
 | 
     * of the drag.  | 
 | 
     */  | 
 | 
 | 
 | 
    public void transferablesFlavorsChanged() { | 
 | 
    }  | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
    protected final void postDragSourceDragEvent(final int targetAction,  | 
 | 
                                                 final int modifiers,  | 
 | 
                                                 final int x, final int y,  | 
 | 
                                                 final int dispatchType) { | 
 | 
 | 
 | 
        final int dropAction =  | 
 | 
            SunDragSourceContextPeer.convertModifiersToDropAction(modifiers,  | 
 | 
                                                                  sourceActions);  | 
 | 
 | 
 | 
        DragSourceDragEvent event =  | 
 | 
            new DragSourceDragEvent(getDragSourceContext(),  | 
 | 
                                    dropAction,  | 
 | 
                                    targetAction & sourceActions,  | 
 | 
                                    modifiers, x, y);  | 
 | 
        EventDispatcher dispatcher = new EventDispatcher(dispatchType, event);  | 
 | 
 | 
 | 
        SunToolkit.invokeLaterOnAppContext(  | 
 | 
            SunToolkit.targetToAppContext(getComponent()), dispatcher);  | 
 | 
 | 
 | 
        startSecondaryEventLoop();  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * upcall from native code  | 
 | 
     */  | 
 | 
 | 
 | 
    protected void dragEnter(final int targetActions,  | 
 | 
                           final int modifiers,  | 
 | 
                           final int x, final int y) { | 
 | 
        postDragSourceDragEvent(targetActions, modifiers, x, y, DISPATCH_ENTER);  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * upcall from native code  | 
 | 
     */  | 
 | 
 | 
 | 
    private void dragMotion(final int targetActions,  | 
 | 
                            final int modifiers,  | 
 | 
                            final int x, final int y) { | 
 | 
        postDragSourceDragEvent(targetActions, modifiers, x, y, DISPATCH_MOTION);  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * upcall from native code  | 
 | 
     */  | 
 | 
 | 
 | 
    private void operationChanged(final int targetActions,  | 
 | 
                                  final int modifiers,  | 
 | 
                                  final int x, final int y) { | 
 | 
        postDragSourceDragEvent(targetActions, modifiers, x, y, DISPATCH_CHANGED);  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * upcall from native code  | 
 | 
     */  | 
 | 
 | 
 | 
    protected final void dragExit(final int x, final int y) { | 
 | 
        DragSourceEvent event =  | 
 | 
            new DragSourceEvent(getDragSourceContext(), x, y);  | 
 | 
        EventDispatcher dispatcher =  | 
 | 
            new EventDispatcher(DISPATCH_EXIT, event);  | 
 | 
 | 
 | 
        SunToolkit.invokeLaterOnAppContext(  | 
 | 
            SunToolkit.targetToAppContext(getComponent()), dispatcher);  | 
 | 
 | 
 | 
        startSecondaryEventLoop();  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * upcall from native code  | 
 | 
     */  | 
 | 
 | 
 | 
    private void dragMouseMoved(final int targetActions,  | 
 | 
                                final int modifiers,  | 
 | 
                                final int x, final int y) { | 
 | 
        postDragSourceDragEvent(targetActions, modifiers, x, y,  | 
 | 
                                DISPATCH_MOUSE_MOVED);  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * upcall from native code via implemented class (do)  | 
 | 
     */  | 
 | 
 | 
 | 
    protected final void dragDropFinished(final boolean success,  | 
 | 
                                          final int operations,  | 
 | 
                                          final int x, final int y) { | 
 | 
        DragSourceEvent event =  | 
 | 
            new DragSourceDropEvent(getDragSourceContext(),  | 
 | 
                                    operations & sourceActions,  | 
 | 
                                    success, x, y);  | 
 | 
        EventDispatcher dispatcher =  | 
 | 
            new EventDispatcher(DISPATCH_FINISH, event);  | 
 | 
 | 
 | 
        SunToolkit.invokeLaterOnAppContext(  | 
 | 
            SunToolkit.targetToAppContext(getComponent()), dispatcher);  | 
 | 
 | 
 | 
        startSecondaryEventLoop();  | 
 | 
        setNativeContext(0);  | 
 | 
        dragImage = null;  | 
 | 
        dragImageOffset = null;  | 
 | 
    }  | 
 | 
 | 
 | 
    public static void setDragDropInProgress(boolean b)  | 
 | 
      throws InvalidDnDOperationException { | 
 | 
        synchronized (SunDragSourceContextPeer.class) { | 
 | 
            if (dragDropInProgress == b) { | 
 | 
                throw new InvalidDnDOperationException(getExceptionMessage(b));  | 
 | 
            }  | 
 | 
            dragDropInProgress = b;  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public static boolean checkEvent(AWTEvent event) { | 
 | 
        if (discardingMouseEvents && event instanceof MouseEvent) { | 
 | 
            MouseEvent mouseEvent = (MouseEvent)event;  | 
 | 
            if (!(mouseEvent instanceof SunDropTargetEvent)) { | 
 | 
                return false;  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return true;  | 
 | 
    }  | 
 | 
 | 
 | 
    public static void checkDragDropInProgress()  | 
 | 
      throws InvalidDnDOperationException { | 
 | 
        if (dragDropInProgress) { | 
 | 
            throw new InvalidDnDOperationException(getExceptionMessage(true));  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static String getExceptionMessage(boolean b) { | 
 | 
        return b ? "Drag and drop in progress" : "No drag in progress";  | 
 | 
    }  | 
 | 
 | 
 | 
    public static int convertModifiersToDropAction(final int modifiers,  | 
 | 
                                                   final int supportedActions) { | 
 | 
        int dropAction = DnDConstants.ACTION_NONE;  | 
 | 
 | 
 | 
          | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
         */  | 
 | 
        switch (modifiers & (InputEvent.SHIFT_DOWN_MASK |  | 
 | 
                             InputEvent.CTRL_DOWN_MASK)) { | 
 | 
        case InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK:  | 
 | 
            dropAction = DnDConstants.ACTION_LINK; break;  | 
 | 
        case InputEvent.CTRL_DOWN_MASK:  | 
 | 
            dropAction = DnDConstants.ACTION_COPY; break;  | 
 | 
        case InputEvent.SHIFT_DOWN_MASK:  | 
 | 
            dropAction = DnDConstants.ACTION_MOVE; break;  | 
 | 
        default:  | 
 | 
            if ((supportedActions & DnDConstants.ACTION_MOVE) != 0) { | 
 | 
                dropAction = DnDConstants.ACTION_MOVE;  | 
 | 
            } else if ((supportedActions & DnDConstants.ACTION_COPY) != 0) { | 
 | 
                dropAction = DnDConstants.ACTION_COPY;  | 
 | 
            } else if ((supportedActions & DnDConstants.ACTION_LINK) != 0) { | 
 | 
                dropAction = DnDConstants.ACTION_LINK;  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
        return dropAction & supportedActions;  | 
 | 
    }  | 
 | 
 | 
 | 
    private void cleanup() { | 
 | 
        trigger = null;  | 
 | 
        component = null;  | 
 | 
        cursor = null;  | 
 | 
        dragSourceContext = null;  | 
 | 
        SunDropTargetContextPeer.setCurrentJVMLocalSourceTransferable(null);  | 
 | 
        SunDragSourceContextPeer.setDragDropInProgress(false);  | 
 | 
    }  | 
 | 
 | 
 | 
    private class EventDispatcher implements Runnable { | 
 | 
 | 
 | 
        private final int dispatchType;  | 
 | 
 | 
 | 
        private final DragSourceEvent event;  | 
 | 
 | 
 | 
        EventDispatcher(int dispatchType, DragSourceEvent event) { | 
 | 
            switch (dispatchType) { | 
 | 
            case DISPATCH_ENTER:  | 
 | 
            case DISPATCH_MOTION:  | 
 | 
            case DISPATCH_CHANGED:  | 
 | 
            case DISPATCH_MOUSE_MOVED:  | 
 | 
                if (!(event instanceof DragSourceDragEvent)) { | 
 | 
                    throw new IllegalArgumentException("Event: " + event); | 
 | 
                }  | 
 | 
                break;  | 
 | 
            case DISPATCH_EXIT:  | 
 | 
                break;  | 
 | 
            case DISPATCH_FINISH:  | 
 | 
                if (!(event instanceof DragSourceDropEvent)) { | 
 | 
                    throw new IllegalArgumentException("Event: " + event); | 
 | 
                }  | 
 | 
                break;  | 
 | 
            default:  | 
 | 
                throw new IllegalArgumentException("Dispatch type: " + | 
 | 
                                                   dispatchType);  | 
 | 
            }  | 
 | 
 | 
 | 
            this.dispatchType  = dispatchType;  | 
 | 
            this.event         = event;  | 
 | 
        }  | 
 | 
 | 
 | 
        public void run() { | 
 | 
            DragSourceContext dragSourceContext =  | 
 | 
                SunDragSourceContextPeer.this.getDragSourceContext();  | 
 | 
            try { | 
 | 
                switch (dispatchType) { | 
 | 
                case DISPATCH_ENTER:  | 
 | 
                    dragSourceContext.dragEnter((DragSourceDragEvent)event);  | 
 | 
                    break;  | 
 | 
                case DISPATCH_MOTION:  | 
 | 
                    dragSourceContext.dragOver((DragSourceDragEvent)event);  | 
 | 
                    break;  | 
 | 
                case DISPATCH_CHANGED:  | 
 | 
                    dragSourceContext.dropActionChanged((DragSourceDragEvent)event);  | 
 | 
                    break;  | 
 | 
                case DISPATCH_EXIT:  | 
 | 
                    dragSourceContext.dragExit(event);  | 
 | 
                    break;  | 
 | 
                case DISPATCH_MOUSE_MOVED:  | 
 | 
                    dragSourceContext.dragMouseMoved((DragSourceDragEvent)event);  | 
 | 
                    break;  | 
 | 
                case DISPATCH_FINISH:  | 
 | 
                    try { | 
 | 
                        dragSourceContext.dragDropEnd((DragSourceDropEvent)event);  | 
 | 
                    } finally { | 
 | 
                        SunDragSourceContextPeer.this.cleanup();  | 
 | 
                    }  | 
 | 
                    break;  | 
 | 
                default:  | 
 | 
                    throw new IllegalStateException("Dispatch type: " + | 
 | 
                                                    dispatchType);  | 
 | 
                }  | 
 | 
            } finally { | 
 | 
                 SunDragSourceContextPeer.this.quitSecondaryEventLoop();  | 
 | 
            }  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |