/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* 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/.
*/
package com.rapidminer.gui.dnd;
import java.awt.datatransfer.Transferable;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.Icon;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.TransferHandler;
import com.rapidminer.gui.RapidMinerGUI;
import com.rapidminer.gui.flow.processrendering.annotations.model.WorkflowAnnotation;
import com.rapidminer.gui.operatortree.actions.CutCopyPasteDeleteAction;
import com.rapidminer.gui.operatortree.actions.DeleteOperatorAction;
import com.rapidminer.operator.Operator;
import com.rapidminer.operator.ProcessRootOperator;
/**
* Transfer handler that supports dragging operators and workflow annotations.
*
* @author Simon Fischer, Marco Boeck
*
*/
public abstract class OperatorTransferHandler extends AbstractPatchedTransferHandler {
private static final long serialVersionUID = 1L;
/** Returns a list of operators selected for dragging out of this component. */
protected abstract List<Operator> getDraggedOperators();
/**
* Returns the copied/cut workflow annotation.
*
* @return the annotation or {@code null}
*/
protected WorkflowAnnotation getDraggedAnnotation() {
return null;
}
// General
@Override
public Icon getVisualRepresentation(Transferable transferable) {
return null;
}
// Drag Support
@Override
public int getSourceActions(JComponent c) {
return COPY_OR_MOVE;
}
@Override
public Transferable createTransferable(JComponent c) {
// first, try operators
List<Operator> operators = getDraggedOperators();
if (operators != null && !operators.isEmpty()) {
// remove children
Iterator<Operator> i = operators.iterator();
while (i.hasNext()) {
Operator op = i.next();
Operator parent = op.getParent();
while (parent != null) {
if (operators.contains(parent)) {
i.remove();
continue;
}
parent = parent.getParent();
}
}
// prevent copying of the process root operator as it only results in error messages
// when pasting anyway
if (operators.size() == 1 && operators.get(0) instanceof ProcessRootOperator) {
return null;
}
return new TransferableOperator(operators.toArray(new Operator[operators.size()]));
} else {
// no operators, try workflow annotations
WorkflowAnnotation anno = getDraggedAnnotation();
// neither operators nor annotations, give up
if (anno == null) {
return null;
}
return new TransferableAnnotation(anno);
}
}
@Override
protected void exportDone(JComponent source, Transferable data, int action) {
if (data instanceof TransferableOperator) {
switch (action) {
case MOVE:
TransferableOperator top = (TransferableOperator) data;
Operator parent = null;
for (Operator operator : top.getOperators()) {
if (parent == null) {
parent = operator.getParent();
}
operator.removeAndKeepConnections(Arrays.asList(top.getOperators()));
}
if (parent != null) {
RapidMinerGUI.getMainFrame().selectOperator(parent);
}
break;
default:
// do nothing
}
}
if (data instanceof TransferableAnnotation) {
switch (action) {
case MOVE:
TransferableAnnotation anno = (TransferableAnnotation) data;
RapidMinerGUI.getMainFrame().getProcessPanel().getAnnotationsHandler().getModel()
.deleteAnnotation(anno.getAnnotation());
break;
default:
// do nothing
}
}
super.exportDone(source, data, action);
}
public static void installMenuItems(JPopupMenu editmenu) {
installMenuItems(editmenu, false);
}
public static void installMenuItems(JPopupMenu editmenu, boolean enableCutCopy) {
if (enableCutCopy) {
editmenu.add(CutCopyPasteDeleteAction.CUT_ACTION);
editmenu.add(CutCopyPasteDeleteAction.COPY_ACTION);
editmenu.add(CutCopyPasteDeleteAction.PASTE_ACTION);
editmenu.add(CutCopyPasteDeleteAction.DELETE_ACTION);
} else {
editmenu.add(CutCopyPasteDeleteAction.CUT_ACTION).setEnabled(false);
editmenu.add(CutCopyPasteDeleteAction.COPY_ACTION).setEnabled(false);
editmenu.add(CutCopyPasteDeleteAction.PASTE_ACTION);
editmenu.add(CutCopyPasteDeleteAction.DELETE_ACTION).setEnabled(false);
}
}
public static void installMenuItems(JMenu editmenu) {
editmenu.add(CutCopyPasteDeleteAction.CUT_ACTION);
editmenu.add(CutCopyPasteDeleteAction.COPY_ACTION);
editmenu.add(CutCopyPasteDeleteAction.PASTE_ACTION);
editmenu.add(CutCopyPasteDeleteAction.DELETE_ACTION);
}
public static void addToActionMap(JComponent component) {
ActionMap actionMap = component.getActionMap();
actionMap.put(TransferHandler.getCutAction().getValue(Action.NAME), TransferHandler.getCutAction());
actionMap.put(TransferHandler.getCopyAction().getValue(Action.NAME), TransferHandler.getCopyAction());
actionMap.put(TransferHandler.getPasteAction().getValue(Action.NAME), TransferHandler.getPasteAction());
actionMap.put(DeleteOperatorAction.getActionName(), new DeleteOperatorAction());
// only required if you have not set the menu accelerators
InputMap inputMap = component.getInputMap();
inputMap.put(KeyStroke.getKeyStroke("ctrl X"), TransferHandler.getCutAction().getValue(Action.NAME));
inputMap.put(KeyStroke.getKeyStroke("ctrl C"), TransferHandler.getCopyAction().getValue(Action.NAME));
inputMap.put(KeyStroke.getKeyStroke("ctrl V"), TransferHandler.getPasteAction().getValue(Action.NAME));
inputMap.put(KeyStroke.getKeyStroke("del"), DeleteOperatorAction.getActionName());
}
}