|
Cut, Copy and Paste
in Java |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
Component that supports the actionsTransferHandler
TransferHandler (cont.)import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
/**
* An ActionForwarder keeps track of which GUI Component has the
* focus and forwards actionPerformed messages to the appropriate
* Component.
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class ActionForwarder implements ActionListener, PropertyChangeListener
{
private JComponent focusOwner;
/**
* Default Constructor.
*/
public ActionForwarder()
{
focusOwner = null;
}
/**
* 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 instanceof JComponent)
{
focusOwner = (JComponent)source;
}
else
{
focusOwner = null;
}
}
/**
* Handle actionPerformed messages. Specifically, forward them to
* the Component with the focus (if that Component has an
* appropriate Action).
*
* @param ae The event that generated the message.
*/
public void actionPerformed(ActionEvent e)
{
if (focusOwner == null) return;
String actionCommand = (String)e.getActionCommand();
Action action = focusOwner.getActionMap().get(actionCommand);
if (action != null)
{
action.actionPerformed(new ActionEvent(focusOwner, ActionEvent.ACTION_PERFORMED, null));
}
}
}
TransferHandler (cont.)ActionForwarder in the Application KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
ActionForwarder forwarder = new ActionForwarder();
manager.addPropertyChangeListener("permanentFocusOwner", forwarder);
// Enable the GUI components to indicate when they have the focus
manager.addPropertyChangeListener("permanentFocusOwner", left);
manager.addPropertyChangeListener("permanentFocusOwner", right);
TransferHandler (cont.) 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));
TransferHandler (cont.)TransferHandler
import java.awt.*;
/**
* The requirements of a Component that can transfer an Image
* (e.g., using drag-and-drop or cut/copy/paste).
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public interface ImageTransferer
{
/**
* Get the current image.
*
* @return The Image
*/
public abstract Image getImage();
/**
* Get the source actions supported by this ImageTransferer.
*
* @return TransferHandler.MOVE or TransferHandler.COPY
*/
public abstract int getSourceActions();
/**
* Set the current image.
*
* @param The Image to use
*/
public abstract void setImage(Image image);
}
TransferHandler
Transferable
import java.awt.*;
import java.awt.datatransfer.*;
/**
* A Transferable wrapper for an Image object.
*
* @author Prof. David Bernstein, James Madison University
* @version For use with an ImageTransferHandler
*/
public class ImageSelection implements Transferable
{
public static final DataFlavor IMAGE_FLAVOR = DataFlavor.imageFlavor;
private Image image;
/**
* Construct an ImageSelection.
*
* @param image The Image to wrap
*/
public ImageSelection(Image image)
{
this.image = image;
}
/**
* Get the DataFlavor objects supported by this Transferable.
*
* @return The DataFlavor objects
*/
public DataFlavor[] getTransferDataFlavors()
{
return new DataFlavor[] { DataFlavor.imageFlavor };
}
/**
* Is the given DataFlavor supported by this Transferable?
*
* @param DataFlavor The DataFlavor of interest
* @return true if it is supported; false otherwise
*/
public boolean isDataFlavorSupported(DataFlavor flavor)
{
for (DataFlavor supported: getTransferDataFlavors())
{
if (flavor.equals(supported)) return true;
}
return false;
}
/**
* Get the Transferable Object for a particular DataFlavor.
*
* @param flavor The DataFlavor of interest
*/
public Object getTransferData(DataFlavor flavor) throws UnsupportedFlavorException
{
if (!isDataFlavorSupported(flavor)) throw new UnsupportedFlavorException(flavor);
return image;
}
}
TransferHandler
TransferHandler
import java.awt.*;
import java.io.IOException;
import java.awt.datatransfer.*;
import javax.swing.*;
/**
* A TransferHandler that supports DnD and CCP on Component objects
* that implement the ImageTransferer interface.
*
* @author Prof. David Bernstein, James Madison University
* @version 1.0
*/
public class ImageTransferHandler extends TransferHandler
{
private static final long serialVersionUID = 1L;
private boolean shouldCutWhenDone;
private ImageTransferer source;
/**
* Import the Transferable in the TransferSupport into the
* JComponent in the TransferSupport.
*
* @param support The TransferSupport
* @return true if the data was imported; false otherwise
*/
public boolean importData(TransferHandler.TransferSupport support)
{
JComponent c = (JComponent)support.getComponent();
Transferable t = support.getTransferable();
shouldCutWhenDone = false;
if ((source != c) && canImport(support))
{
ImageTransferer component = (ImageTransferer)c;
try
{
Image image = (Image)t.getTransferData(ImageSelection.IMAGE_FLAVOR);
component.setImage(image);
shouldCutWhenDone = true;
return true;
}
catch (IOException | UnsupportedFlavorException e)
{
return false;
}
}
return false;
}
/**
* Create a Transferable using the contents of the given JComponent.
*
*/
protected Transferable createTransferable(JComponent c)
{
ImageTransferer component = (ImageTransferer)c;
source = component;
shouldCutWhenDone = true; // By default
return new ImageSelection(component.getImage());
}
/**
* Get the source actions supported by this TransferHandler
* for the given Component.
*
* @param c The Component of interest
* @return The source actions supported (COPY_OR_MOVE)
*/
public int getSourceActions(JComponent c)
{
return COPY_OR_MOVE;
}
/**
* Complete the export process.
*
* @param c The Component
* @param data The Transferable
* @param action The action
*/
protected void exportDone(JComponent c, Transferable data, int action)
{
if ((action == MOVE) && shouldCutWhenDone)
{
ImageTransferer component = (ImageTransferer)c;
component.setImage(null);
}
source = null;
}
/**
* Return true if the Component in the TransferSupport can support one of the
* DataFlavor objects in the TransferSupport.
*
* @param support The TransferSupport
*/
public boolean canImport(TransferHandler.TransferSupport support)
{
DataFlavor[] flavors = support.getDataFlavors();
for (DataFlavor flavor: flavors)
{
if (flavor.equals(ImageSelection.IMAGE_FLAVOR)) return true;
}
return false;
}
}
TransferHandler
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());
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));
// 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();
}
}