import java.awt.*;
import java.awt.dnd.*;
import javax.swing.*;

/**
 * A Component that supports drag and drop for Image objects.
 * 
 * @author  Prof. David Bernstein
 * @version DnD (Move Only); Standard TransferHandler
 */
public class ImagePanel extends JPanel implements DropTargetListener, DragGestureListener, DragSourceListener
{
  private static final long serialVersionUID = 1L;

  private boolean       dragEnabled;
  private DragSource    source;
  private Image         image;

  
  /**
   * Default Constructor.
   */
  public ImagePanel()
  {
    image = null;
    
    // Create a DropTarget for this Component.
    // Note: This Component is also the DropTargetListener.
    new DropTarget(this, this);
    
    // Create a DragSource for this Component.
    // Note: This Component is also the DropTargetListener.
    source = new DragSource();
    source.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, this);

    
    // Use a bean-oriented handler for objects with an image property
    // (i.e., with getImage() and setImage() methods)
    TransferHandler handler = new TransferHandler("image");
    setTransferHandler(handler);
}

  // Methods required by image beans

  /**
   * Get the Image associated with this ImagePanel.
   * 
   * This method is required so that this Component is a bean
   * with the image property.
   * 
   * @return  The Image
   */
  public Image getImage()
  {
    return image;
  }
  
  /**
   * Set the Image on this Component.
   * 
   * This method is required so that this Component is a bean
   * with the image property.
   * 
   * @param image  The Image to use.
   */
  public void setImage(Image image)
  {
    this.image = image;
    repaint();
  }
  
  
  // Methods that provide the desired GUI functionality

  /**
   * Is drag enabled for this Component?
   * 
   * @return true if enabled; false otherwise
   */
  public boolean getDragEnabled()
  {
    return dragEnabled;
  }

  /**
   * Render this Component.
   * 
   * @param g  The rendering engine to use
   */
  public void paint(Graphics g)
  {
    super.paint(g);
    
    if (image != null)
    {
      int width  = getWidth();
      int height = getHeight();
      int iw = image.getWidth(null);
      int ih = image.getHeight(null);
      
      g.drawImage(image, width/2 - iw/2, height/2 - ih/2, null);
    }
  }
  
  /**
   * Determine whether drag is enabled on this Component.
   * 
   * @param enabled  true to enable; false to disable
   */
  public void setDragEnabled(boolean enabled)
  {
    dragEnabled = enabled;
  }
   
  
  // Methods required of DropTargetListener objects
  
  /**
   * Handle dragEnter messages.
   * 
   * @param dtde The event that generated the message
   */
  public void dragEnter(DropTargetDragEvent dtde)
  {
  }

  /**
   * Handle dragOver messages.
   * 
   * @param dtde The event that generated the message
   */
  public void dragOver(DropTargetDragEvent dtde)
  {
  }

  /**
   * Handle dropActionChanged messages.
   * 
   * @param dtde The event that generated the message
   */
  public void dropActionChanged(DropTargetDragEvent dtde)
  {
  }

  /**
   * Handle dragEnter messages.
   * 
   * @param dtde The event that generated the message
   */
  public void dragExit(DropTargetEvent dte)
  {
  }

  /**
   * Handle drop messages.
   * 
   * @param dtde The event that generated the message
   */
  public void drop(DropTargetDropEvent dtde)
  {
    // Invoke the TransferHandler object's importData() method.
    // The TransferHandler will, in turn, invoke this Component's
    // setImage() method.
    TransferHandler.TransferSupport support;
    support = new TransferHandler.TransferSupport(this, dtde.getTransferable());
    getTransferHandler().importData(support);
  }

  // Methods required by DragSourceListener objects
  
  /**
   * Handle dragEnter messages.
   * 
   * @param dsde  The event that generated the message
   */
  public void dragEnter(DragSourceDragEvent dsde)
  {
  }

  /**
   * Handle dragOver messages.
   * 
   * @param dsde  The event that generated the message
   */
  public void dragOver(DragSourceDragEvent dsde)
  {
  }
  
  /**
   * Handle dropActionChanged messages.
   * 
   * @param dsde  The event that generated the message
   */
  public void dropActionChanged(DragSourceDragEvent dsde)
  {
  }
  
  /**
   * Handle dragExit messages.
   * 
   * @param dsde  The event that generated the message
   */
  public void dragExit(DragSourceEvent dse) {}
  
  /**
   * Handle dragDropEnd messages.
   * 
   * @param dsde  The event that generated the message
   */
  public void dragDropEnd(DragSourceDropEvent dsde) 
  {
    // Since this Component only supports move actions,
    // delete the Image.
    setImage(null);
  }

  
  // Methods required by DragGestureListener objects
  
  /**
   * Handle dragGestureRecognized messages.
   * 
   * @param dge The event that generated the message 
   */
  public void dragGestureRecognized(DragGestureEvent dge) 
  {
    source.startDrag(dge, DragSource.DefaultMoveDrop, new ImageSelection(image), this);       
  }
}
