/*
This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Affero General Public License as published by the Free
Software Foundation; either version 3 of the License, or (at your option) any
later version.
This program 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along
with this program; if not, see http://www.gnu.org/licenses or write to the Free
Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
*/
package com.servoy.j2db.dnd;
import java.awt.Component;
import java.awt.Container;
import java.awt.Point;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.DropTarget;
import java.awt.dnd.DropTargetDragEvent;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.TransferHandler;
import javax.swing.UIManager;
import com.servoy.base.scripting.api.IJSEvent.EventType;
import com.servoy.j2db.FormController;
import com.servoy.j2db.component.ComponentFactory;
import com.servoy.j2db.dataprocessing.IRecordInternal;
import com.servoy.j2db.dataprocessing.Record;
import com.servoy.j2db.ui.IComponent;
import com.servoy.j2db.ui.IDataRenderer;
import com.servoy.j2db.util.Debug;
/**
* Class used for handling drag and drop operations in smart client on forms
*
* @author gboros
*/
public class FormDataTransferHandler extends CompositeTransferHandler
{
private static CompositeTransferHandler instance;
public static TransferHandler getInstance()
{
if (instance == null) instance = new FormDataTransferHandler();
return instance;
}
@Override
protected JSDNDEvent createScriptEvent(EventType type, ICompositeDragNDrop ddComponent, Object event)
{
JSDNDEvent jsEvent = super.createScriptEvent(type, ddComponent, event);
if (ddComponent instanceof IFormDataDragNDrop)
{
IFormDataDragNDrop formDataDDComponent = (IFormDataDragNDrop)ddComponent;
jsEvent.setFormName(formDataDDComponent.getDragFormName());
Point location = getEventXY(event);
if (location != null)
{
Object dragSource = ddComponent.getDragSource(location);
if (dragSource instanceof IDataRenderer)
{
IDataRenderer dr = (IDataRenderer)dragSource;
FormController fc = dr.getDataAdapterList().getFormController();
jsEvent.setSource(fc.getFormScope());
}
else if (dragSource instanceof IComponent)
{
jsEvent.setSource(dragSource);
if (dragSource != null)
{
String name = ((IComponent)dragSource).getName();
if (name != null && name.startsWith(ComponentFactory.WEB_ID_PREFIX))
{
name = null;
}
jsEvent.setElementName(name);
}
}
IRecordInternal dragRecord = formDataDDComponent.getDragRecord(location);
if (dragRecord instanceof Record) jsEvent.setRecord((Record)dragRecord);
}
}
return jsEvent;
}
@Override
protected boolean canReplaceDragSource(Object currentDragSource, Object newDragSource, DropTargetDragEvent e)
{
if (currentDragSource instanceof Component && newDragSource instanceof Component)
{
if (currentDragSource != newDragSource)
{
// check if the oldLastDragSource is hidding the newDragSource
Component cCurrentDragSource = (Component)currentDragSource;
Component cNewDragSource = (Component)newDragSource;
Point xy = getEventXY(e);
Container currentDsParent = cCurrentDragSource.getParent();
Container newDsParent = cNewDragSource.getParent();
boolean isCompositeParentFound = cNewDragSource instanceof ICompositeDragNDrop;
while (newDsParent != null && newDsParent != currentDsParent)
{
if (isCompositeParentFound) xy.translate(cNewDragSource.getX(), cNewDragSource.getY());
else isCompositeParentFound = newDsParent instanceof ICompositeDragNDrop;
cNewDragSource = newDsParent;
newDsParent = cNewDragSource.getParent();
}
if (isCompositeParentFound) xy.translate(cNewDragSource.getX(), cNewDragSource.getY());
if (newDsParent != null && newDsParent == currentDsParent)
{
Component visibleComponent = newDsParent.findComponentAt(xy);
return visibleComponent == newDragSource;
}
}
else
{
Object s = e.getSource();
if (s instanceof DropTarget)
{
Component dtc = ((DropTarget)s).getComponent();
if (dtc instanceof IFormDataDragNDrop) return ((IFormDataDragNDrop)dtc).isGridView();
}
}
}
return super.canReplaceDragSource(currentDragSource, newDragSource, e);
}
static final Action cutFormDataAction = new TransferAction("cut");
static final Action copyFormDataAction = new TransferAction("copy");
static final Action pasteFormDataAction = new TransferAction("paste");
public static Action getCopyFormDataAction()
{
return copyFormDataAction;
}
public static Action getCutFormDataAction()
{
return cutFormDataAction;
}
public static Action getPasteFormDataAction()
{
return pasteFormDataAction;
}
static class TransferAction extends AbstractAction
{
TransferAction(String name)
{
super(name);
}
public void actionPerformed(ActionEvent e)
{
Object src = e.getSource();
if (src instanceof JComponent)
{
JComponent c = (JComponent)src;
TransferHandler th = (src instanceof ISupportDragNDropTextTransfer) ? ((ISupportDragNDropTextTransfer)src).getTextTransferHandler()
: c.getTransferHandler();
Clipboard clipboard = getClipboard(c);
String name = (String)getValue(Action.NAME);
Transferable trans = null;
// any of these calls may throw IllegalStateException
try
{
if ((clipboard != null) && (th != null) && (name != null))
{
if ("cut".equals(name))
{
th.exportToClipboard(c, clipboard, MOVE);
}
else if ("copy".equals(name))
{
th.exportToClipboard(c, clipboard, COPY);
}
else if ("paste".equals(name))
{
trans = clipboard.getContents(null);
}
}
}
catch (IllegalStateException ise)
{
// clipboard was unavailable
UIManager.getLookAndFeel().provideErrorFeedback(c);
return;
}
// this is a paste action, import data into the component
if (trans != null)
{
th.importData(c, trans);
}
}
}
/**
* Returns the clipboard to use for cut/copy/paste.
*/
private Clipboard getClipboard(JComponent c)
{
Clipboard clipboard = null;
try
{
clipboard = c.getToolkit().getSystemClipboard();
}
catch (Exception ex)
{
Debug.error("Error getting system clipboard", ex);
}
return clipboard;
}
}
}