package org.openflexo.fge.view; import java.awt.Point; 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.DragSourceContext; 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.MouseEvent; import java.awt.image.BufferedImage; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.SwingUtilities; import org.openflexo.fge.controller.DrawingController; import org.openflexo.fge.controller.DrawingPalette; import org.openflexo.fge.controller.DrawingPalette.PaletteDrawing; import org.openflexo.fge.controller.PaletteElement; import org.openflexo.fge.controller.PaletteElement.PaletteElementGraphicalRepresentation; import org.openflexo.fge.controller.PaletteElement.PaletteElementTransferable; import org.openflexo.toolbox.ToolBox; import sun.awt.dnd.SunDragSourceContextPeer; public class PaletteElementView extends ShapeView<PaletteElement> { private static final Logger logger = Logger.getLogger(PaletteElementView.class.getPackage().getName()); private DragSource dragSource; private DragGestureListener dgListener; private DragSourceListener dsListener; private int dragAction = DnDConstants.ACTION_COPY; private DragGestureRecognizer dgr; private DragGestureRecognizer labelDgr; /* Local controller ONLY */ private DrawingController<PaletteDrawing> paletteController; public PaletteElementView(PaletteElementGraphicalRepresentation aGraphicalRepresentation, DrawingController<PaletteDrawing> controller) { super(aGraphicalRepresentation, controller); this.dgListener = new DGListener(); this.dragSource = DragSource.getDefaultDragSource(); this.dsListener = new DSListener(); this.paletteController = controller; dgr = createDragGestureRecognizer(); // component, action, listener enableDragging(); if (aGraphicalRepresentation.getToolTipText() != null) { setToolTipText(aGraphicalRepresentation.getToolTipText()); } } private DragGestureRecognizer createDragGestureRecognizer() { return dragSource.createDefaultDragGestureRecognizer(this, this.dragAction, this.dgListener); } @Override public String getToolTipText(MouseEvent event) { return getToolTipText(); } @Override public PaletteElementGraphicalRepresentation getGraphicalRepresentation() { return (PaletteElementGraphicalRepresentation) super.getGraphicalRepresentation(); } public PaletteElement getPaletteElement() { return getGraphicalRepresentation().getDrawable(); } public DrawingPalette getPalette() { return getPaletteElement().getPalette(); } public BufferedImage getBuffer() { return getDrawingView().getPaintManager().getScreenshot(getGraphicalRepresentation()); } // =============================================================== // ================== Dnd Stuff ================================= // =============================================================== protected void enableDragging() { dgr.setComponent(this); /** * FIX for bug where element is not draggable when initial click begins on label * * There is a big trick here: the label view is not a subcomponent of view, so dragging on this component will not be seen by * palette element view, so we need here to force disable mouse listeners registered for this palette view */ if (getLabelView() != null) { if (labelDgr == null) { labelDgr = createDragGestureRecognizer(); } getLabelView().disableTextComponentMouseListeners(); labelDgr.setComponent(getLabelView().getTextComponent()); } } protected void disableDragging() { // dgr.setComponent(null); if (getLabelView() != null) { getLabelView().enableTextComponentMouseListeners(); } if (labelDgr != null) { labelDgr.setComponent(null); } } /** * DGListener a listener that will start the drag. has access to top level's dsListener and dragSource * * @see java.awt.dnd.DragGestureListener * @see java.awt.dnd.DragSource * @see java.awt.datatransfer.StringSelection */ class DGListener implements DragGestureListener { /** * Start the drag if the operation is ok. uses java.awt.datatransfer.StringSelection to transfer the label's data * * @param e * the event object */ @Override public void dragGestureRecognized(DragGestureEvent e) { logger.info("dragGestureRecognized"); // if the action is ok we go ahead // otherwise we punt if ((e.getDragAction() & dragAction) == 0) { return; // get the label's text and put it inside a Transferable // Transferable transferable = new StringSelection( // DragLabel.this.getText() ); } Point p = SwingUtilities.convertPoint(e.getComponent(), e.getDragOrigin(), PaletteElementView.this); PaletteElementTransferable transferable = new PaletteElementTransferable(getDrawable(), p); if (ToolBox.isMacOS()) { // Need to call this on MacOS. // Scenario to reproduce issue // 1. Drop a sub process node // 2. Choose create a new subprocess // 3. Try to drop another element-->InvalidDnDOperationException synchronized (SunDragSourceContextPeer.class) { try { SunDragSourceContextPeer.checkDragDropInProgress(); } catch (InvalidDnDOperationException ex) { if (logger.isLoggable(Level.WARNING)) { logger.warning("For some reason there was still a Dnd in progress. Will set it back to false. God knows why this happens"); } if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "Stacktrace for DnD still in progress", ex); } SunDragSourceContextPeer.setDragDropInProgress(false); } } } try { // initial cursor, transferrable, dsource listener e.startDrag(DrawingPalette.dropKO, transferable, dsListener); logger.info("Starting drag for " + getGraphicalRepresentation()); getDrawingView().captureDraggedNode(PaletteElementView.this, e); } catch (Exception idoe) { logger.warning("Unexpected exception " + idoe); } } } /** * DSListener a listener that will track the state of the DnD operation * * @see java.awt.dnd.DragSourceListener * @see java.awt.dnd.DragSource * @see java.awt.datatransfer.StringSelection */ public class DSListener implements DragSourceListener { /** * @param e * the event */ @Override public void dragDropEnd(DragSourceDropEvent e) { // Resets the screenshot stored by the palette view. getDrawingView().resetCapturedNode(); if (!e.getDropSuccess()) { if (logger.isLoggable(Level.INFO)) { logger.info("Dropping was not successful"); } return; } /* * the dropAction should be what the drop target specified in * acceptDrop */ // this is the action selected by the drop target if (e.getDropAction() == DnDConstants.ACTION_MOVE) { setName(""); } } /** * @param e * the event */ @Override public void dragEnter(DragSourceDragEvent e) { DragSourceContext context = e.getDragSourceContext(); // intersection of the users selected action, and the source and // target actions int myaction = e.getDropAction(); if ((myaction & dragAction) != 0) { context.setCursor(DragSource.DefaultCopyDrop); } else { context.setCursor(DragSource.DefaultCopyNoDrop); } } /** * @param e * the event */ @Override public void dragOver(DragSourceDragEvent e) { // interface getPalette().setDragSourceContext(e.getDragSourceContext()); } /** * @param e * the event */ @Override public void dragExit(DragSourceEvent e) { // interface } /** * for example, press shift during drag to change to a link action * * @param e * the event */ @Override public void dropActionChanged(DragSourceDragEvent e) { DragSourceContext context = e.getDragSourceContext(); context.setCursor(DragSource.DefaultCopyNoDrop); } } }