/*
* FrontlineSMS <http://www.frontlinesms.com>
* Copyright 2007, 2008 kiwanja
*
* This file is part of FrontlineSMS.
*
* FrontlineSMS is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at
* your option) any later version.
*
* FrontlineSMS is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with FrontlineSMS. If not, see <http://www.gnu.org/licenses/>.
*/
package net.frontlinesms.plugins.forms.ui;
import java.awt.Component;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.dnd.DragGestureEvent;
import java.awt.dnd.DragGestureListener;
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.DragSourceMotionListener;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.dnd.DropTargetDropEvent;
import java.awt.dnd.DropTargetEvent;
import java.awt.dnd.DropTargetListener;
import java.io.IOException;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import net.frontlinesms.FrontlineUtils;
import net.frontlinesms.plugins.forms.ui.components.PaletteComponent;
import org.apache.log4j.Logger;
/**
* This class is responsible for handling all the drag and drop actions.
*
* @author Carlos Eduardo Genz
* <li> kadu(at)masabi(dot)com
*/
public class DragListener implements Transferable, DragSourceListener, DragGestureListener, DropTargetListener, DragSourceMotionListener {
private static DataFlavor[] flavors;
private Object data;
private DrawingPanel drawingPanel;
private static Logger LOG = FrontlineUtils.getLogger(DragListener.class);
public DragListener(DrawingPanel drawingPanel) {
flavors = new DataFlavor[1];
try {
flavors[0] = new DataFlavor(DataFlavor.javaJVMLocalObjectMimeType);
} catch (ClassNotFoundException e) {
LOG.debug("", e);
}
this.drawingPanel = drawingPanel;
}
public void dragDropEnd(DragSourceDropEvent dsde) {
data = null;
drawingPanel.dragMoved(-1, -1);
}
public void dragEnter(DragSourceDragEvent dsde) {}
public void dragExit(DragSourceEvent dse) {}
public void dragOver(DragSourceDragEvent dsde) {
data = dsde.getSource();
}
public void dropActionChanged(DragSourceDragEvent dsde) {}
public void dragGestureRecognized(DragGestureEvent dge) {
dge.startDrag(null, this, this);
}
public void dragEnter(DropTargetDragEvent dtde) {}
public void dragExit(DropTargetEvent dte) {}
public void dragOver(DropTargetDragEvent dtde) {}
public void drop(DropTargetDropEvent dtde) {
dtde.acceptDrop(dtde.getDropAction());
try {
Object target = dtde.getSource();
Component targ = ((DropTarget) target).getComponent();
Object source = dtde.getTransferable().getTransferData(flavors[0]);
if (source != null) {
Component obj = ((DragSourceContext) source).getComponent();
/**
* We've got 3 different types of drag and drop in our code:
* <li> Drag a component from palette to preview
* <li> Drag a component from preview to the bin
* <li> Drag a component from preview to itself (moving)
*/
if (targ instanceof PreviewPanel) {
// So if we are dragging something to Preview, either we are moving or creating a new component.
if (targ.equals(getContainerParent(obj))) {
// Moving in the preview.
drawingPanel.moveComponentInPreview(getContainerParentDelete(obj), dtde.getLocation().x, dtde.getLocation().y);
} else {
// Adding to preview
drawingPanel.addToPreview((PaletteComponent) obj, dtde.getLocation().x, dtde.getLocation().y);
}
} else if (targ instanceof JLabel) {
// Here we are dragging something to the bin
drawingPanel.deleteFromPreview(getContainerParentDelete(obj));
}
}
dtde.dropComplete(true);
} catch (UnsupportedFlavorException e) {
LOG.debug("", e);
} catch (IOException e) {
LOG.debug("", e);
}
}
/**
* Recursively returns the container being deleted.
*
* @param obj
* @return
*/
private Component getContainerParent(Component obj) {
if (obj == null) return null;
if (obj instanceof PreviewPanel)
return obj;
return getContainerParent(obj.getParent());
}
/**
* Recursively returns the container being deleted.
*
* @param obj
* @return
*/
private Component getContainerParentDelete(Component obj) {
if (obj == null) return null;
if (obj instanceof JPanel || obj instanceof JScrollPane)
return obj;
return getContainerParentDelete(obj.getParent());
}
public void dropActionChanged(DropTargetDragEvent dtde) {}
public DataFlavor[] getTransferDataFlavors() {
return flavors;
}
public boolean isDataFlavorSupported(DataFlavor flavor) {
return flavor.isMimeTypeEqual(DataFlavor.javaJVMLocalObjectMimeType);
}
public synchronized Object getTransferData(DataFlavor flavor) {
return data;
}
public void dragMouseMoved(DragSourceDragEvent dsde) {
drawingPanel.dragMoved(dsde.getX(), dsde.getY());
}
}