/******************************************************************************* * Copyright (c) 2007, 2010 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.g2d.dnd; import java.awt.Component; import java.awt.Cursor; import java.awt.Point; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragGestureRecognizer; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.InvalidDnDOperationException; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import java.util.Collection; import java.util.TooManyListenersException; import org.simantics.g2d.canvas.Hints; import org.simantics.g2d.canvas.ICanvasContext; import org.simantics.g2d.canvas.impl.AbstractCanvasParticipant; import org.simantics.g2d.canvas.impl.DependencyReflection.Dependency; import org.simantics.g2d.participant.MouseUtil; import org.simantics.g2d.participant.MouseUtil.ButtonInfo; import org.simantics.g2d.participant.MouseUtil.MouseInfo; import org.simantics.scenegraph.g2d.events.EventHandlerReflection.EventHandler; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseButtonReleasedEvent; import org.simantics.scenegraph.g2d.events.MouseEvent.MouseDragBegin; import org.simantics.utils.ui.ErrorLogger; /** * This participant handles drop operations. * * To implement a drop operation add an implementation of IDragParticipant to the canvas. * * Drag interactor is added by chassis. * * @author Toni Kalajainen */ public class DragInteractor extends AbstractCanvasParticipant implements DragSourceListener { private final Component component; private IDragSourceParticipant dragParticipant; @Dependency MouseUtil mouseUtil; public DragInteractor(Component component) { super(); this.component = component; } @Override public void addedToContext(ICanvasContext ctx) { super.addedToContext(ctx); installDragSource(); } @Override public void removedFromContext(ICanvasContext ctx) { DRAG_SOURCE.removeDragSourceListener(this); super.removedFromContext(ctx); } int getAllowedOps() { int result = 0; for (IDragSourceParticipant p : getDragParticipants()) result |= p.getAllowedOps(); return result; } class MyDragGestureRecognizer extends DragGestureRecognizer { private static final long serialVersionUID = 920532285869166322L; protected MyDragGestureRecognizer(DragSource ds, Component c, int actionMask) { super(ds, c, actionMask); } @Override protected void registerListeners() { } @Override protected void unregisterListeners() { } public boolean handleDrag(MouseDragBegin me) { for (IDragSourceParticipant p : getDragParticipants()) { int op = p.canDrag(me); if (op==0) continue; int x = (int)me.controlPosition.getX(); int y = (int)me.controlPosition.getY(); InputEvent awtie = new MouseEvent(component, 0, me.time, 0, x, y, 1, false); appendEvent(awtie); fireDragGestureRecognized(op, new Point(x, y)); return true; } return false; } } static DragSource DRAG_SOURCE = new DragSource(); MyDragGestureRecognizer dgr; @EventHandler(priority = -1000) public boolean handleDrag(MouseDragBegin me) { return dgr.handleDrag(me); } void installDragSource() { Integer actionMask = getHint(Hints.KEY_ALLOWED_DRAG_ACTIONS); if (actionMask == null) actionMask = DnDConstants.ACTION_COPY_OR_MOVE | DnDConstants.ACTION_REFERENCE; dgr = new MyDragGestureRecognizer(DRAG_SOURCE, component, actionMask); try { dgr.addDragGestureListener(new DragGestureListener() { @Override public void dragGestureRecognized(DragGestureEvent e) { // Start drag try { // Create transferable from selection Transferable transferable = null; IDragSourceParticipant activeParticipant = null; for (IDragSourceParticipant p : getDragParticipants()) { transferable = p.dragStart(e); if (transferable!=null) { activeParticipant = p; break; } } if (transferable==null) return; //initial cursor, transferable, dsource listener // int allowedOps = activeParticipant.getAllowedOps(); // int action = e.getDragAction(); // Cursor cursor = getCursor(action, allowedOps); // DRAG_SOURCE.startDrag(e, cursor, transferable, DragInteractor.this); DRAG_SOURCE.startDrag(e, null, transferable, DragInteractor.this); DragInteractor.this.dragParticipant = activeParticipant; // synthetisize mouse button release MouseInfo mi = mouseUtil.getMouseInfo(0); if (mi!=null) { long time = System.currentTimeMillis(); for (ButtonInfo bi : mi.getButtonInfos()) { if (!bi.down) continue; // FIXME : screenPos null (requires changes in MouseInfo) MouseButtonReleasedEvent mbre = new MouseButtonReleasedEvent(null, time, mi.mouseId, mi.buttons, bi.stateMask, bi.button, time-bi.eventTime, mi.controlPosition, null); getContext().getEventQueue().queueEvent(mbre); } } } catch( InvalidDnDOperationException idoe ) { ErrorLogger.defaultLogError(idoe); } }}); } catch (TooManyListenersException e) { // Should not happen e.printStackTrace(); } DRAG_SOURCE.addDragSourceListener(this); } protected Collection getDragParticipants() { return getContext().getItemsByClass(IDragSourceParticipant.class); } @Override public void dragEnter(final DragSourceDragEvent dsde) { if (dragParticipant==null) return; syncExec(new Runnable() { @Override public void run() { if (dragParticipant==null) return; // int allowedOps = dragParticipant.getAllowedOps(); // int action = dsde.getDropAction(); // Cursor cursor = getCursor(action, allowedOps); // dsde.getDragSourceContext().setCursor( cursor ); dragParticipant.dragEnter(dsde); }}); } @Override public void dragDropEnd(final DragSourceDropEvent dsde) { if (dragParticipant==null) return; syncExec(new Runnable() { @Override public void run() { if (dragParticipant==null) return; dragParticipant.dragDropEnd(dsde); endDrag(); } }); } @Override public void dragExit(final DragSourceEvent dse) { if (dragParticipant==null) return; syncExec(new Runnable() { @Override public void run() { if (dragParticipant==null) return; dragParticipant.dragExit(dse); endDrag(); } }); } @Override public void dragOver(final DragSourceDragEvent dsde) { syncExec(new Runnable() { @Override public void run() { if (dragParticipant==null) return; dragParticipant.dragOver(dsde); } }); } public static Cursor getCursor(int action, int allowedOps) { boolean allowed = (action & allowedOps) != 0; if (action == DnDConstants.ACTION_LINK) return allowed ? DragSource.DefaultLinkDrop : DragSource.DefaultLinkNoDrop; else if (action == DnDConstants.ACTION_COPY) return allowed ? DragSource.DefaultCopyDrop : DragSource.DefaultCopyNoDrop; else if (action == DnDConstants.ACTION_MOVE) return allowed ? DragSource.DefaultMoveDrop : DragSource.DefaultMoveNoDrop; return DragSource.DefaultCopyNoDrop; } @Override public void dropActionChanged(final DragSourceDragEvent dsde) { if (dragParticipant==null) return; syncExec(new Runnable() { @Override public void run() { if (dragParticipant==null) return; // int allowedOps = dragParticipant.getAllowedOps(); // int action = dsde.getDropAction(); // Cursor cursor = getCursor(action, allowedOps); // dsde.getDragSourceContext().setCursor( cursor ); dragParticipant.dropActionChanged(dsde); } }); } public void endDrag() { Collection dragPainters = getContext().getItemsByClass(DragPainter.class); if (dragPainters.size()==0) return; for (DragPainter dp : dragPainters) dp.remove(); dragParticipant = null; getContext().getContentContext().setDirty(); } }