import java.awt.*;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;

/**
 * A Component that supports drag-and-drop and cut/copy/paste
 * for Image objects.
 * 
 * @author  Prof. David Bernstein
 * @version Using a custom Transferable and TransferHandler
 */
public class ImagePanel extends JPanel implements ImageTransferer, PropertyChangeListener
{
  private static final long serialVersionUID = 1L;

  private boolean      dragEnabled;
  private Image        image;
  
  /**
   * Default Constructor.
   */
  public ImagePanel(String id)
  {
    super();
    image = null;
    setTransferHandler(new ImageTransferHandler());
    
//[CCP
    setFocusable(true);

    ActionMap map = getActionMap();
    map.put(TransferHandler.getCutAction().getValue(Action.NAME),
            TransferHandler.getCutAction());
    map.put(TransferHandler.getCopyAction().getValue(Action.NAME),
            TransferHandler.getCopyAction());
    map.put(TransferHandler.getPasteAction().getValue(Action.NAME),
            TransferHandler.getPasteAction());
    
    InputMap imap = this.getInputMap();
    imap.put(KeyStroke.getKeyStroke("ctrl X"),
        TransferHandler.getCutAction().getValue(Action.NAME));
    imap.put(KeyStroke.getKeyStroke("ctrl C"),
        TransferHandler.getCopyAction().getValue(Action.NAME));
    imap.put(KeyStroke.getKeyStroke("ctrl V"),
        TransferHandler.getPasteAction().getValue(Action.NAME));
//]CCP

    // Forward mousePressed messages to a TrasnferHandler at
    // the start of a drag
    addMouseListener(
        new MouseAdapter()
        // An anonymous inner class that overrides mousePressed() in MouseAdapter
        {
          public void mousePressed(MouseEvent e) 
          {
            JComponent c = (JComponent)e.getSource();
            TransferHandler handler = c.getTransferHandler();
            handler.exportAsDrag(c, e, TransferHandler.MOVE);
          }
        }
    );
    
  }

  // Methods required by ImageTransferer

  /**
   * Get the Image associated with this ImagePanel.
   * 
   * @return  The Image
   */
  public Image getImage()
  {
    return image;
  }
  
  /**
   * Get the source actions supported by this ImageTransferer.
   * 
   * @return TransferHandler.MOVE or TransferHandler.COPY
   */
  public int getSourceActions()
  {
    return TransferHandler.COPY_OR_MOVE;
  }
  
  /**
   * Set the Image on this Component.
   * 
   * @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 by PropertyChangeListener

  /**
   * Handle propertyChange messages. Specifically, keep track of
   * the Component with the focus.
   * 
   * @param pce  The event that generated the message
   */
  public void propertyChange(PropertyChangeEvent pce) 
  {
    Object source = pce.getNewValue();

    if (source == this) setBackground(Color.WHITE);
    else                setBackground(Color.GRAY);
    repaint();
  }
}
