/**
* 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.operator.ports.impl;
import com.rapidminer.gui.tools.ResourceAction;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.operator.IOMultiplier;
import com.rapidminer.operator.OperatorCreationException;
import com.rapidminer.operator.ports.InputPort;
import com.rapidminer.operator.ports.OutputPort;
import com.rapidminer.operator.ports.Port;
import com.rapidminer.operator.ports.PortException;
import com.rapidminer.tools.I18N;
import com.rapidminer.tools.LogService;
import com.rapidminer.tools.OperatorService;
import java.awt.Component;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import javax.swing.Action;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
/**
*
* @author Simon Fischer, Tobias Malbrecht, Nils Woehler
*/
public class CannotConnectPortException extends PortException {
public static final int HIDE_DELAY = 2500;
private static final long serialVersionUID = 5242982041478562116L;
private final OutputPort source;
private final InputPort dest;
public CannotConnectPortException(OutputPort source, InputPort dest, InputPort sourceDest, OutputPort destSource) {
super("Cannot connect " + source.getSpec() + " to " + dest.getSpec());
this.source = source;
this.dest = dest;
}
public CannotConnectPortException(OutputPort source, InputPort dest, InputPort sourceDest) {
super("Cannot connect " + source.getSpec() + " to " + dest.getSpec());
this.source = source;
this.dest = dest;
}
public CannotConnectPortException(OutputPort source, InputPort dest, OutputPort destSource) {
super("Cannot connect " + source.getSpec() + " to " + dest.getSpec());
this.source = source;
this.dest = dest;
}
@Override
public boolean hasRepairOptions() {
return true;
}
@Override
public void showRepairPopup(Component parent, Point popupLocation) {
// remember initial state first
final boolean sourceConnected = source.isConnected();
final InputPort oldDest = source.getDestination();
// connect ports in any case
source.lock();
dest.lock();
if (sourceConnected) {
source.disconnect();
}
if (dest.isConnected()) {
dest.getSource().disconnect();
}
source.connectTo(dest);
source.unlock();
dest.unlock();
if (sourceConnected) {
final JPopupMenu menu = new JPopupMenu();
// give the user the possibility to create IO multiplier instead
Action addIOMultiplierActions = new ResourceAction("cannot_connect.option.insert_multiplier") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent e) {
final List<Port> toUnlock = new LinkedList<Port>();
try {
// lock old dest port
toUnlock.add(oldDest);
oldDest.lock();
// lock source port
toUnlock.add(source);
source.lock();
// lock dest port
toUnlock.add(dest);
dest.lock();
// disconnect source
source.disconnect();
// create IO multiplier
IOMultiplier multiplier = OperatorService.createOperator(IOMultiplier.class);
// connect source to multiplier
source.getPorts().getOwner().getConnectionContext().addOperator(multiplier);
source.connectTo(multiplier.getInputPorts().getPortByIndex(0));
// connect multiplier to old dest and new dest
multiplier.getOutputPorts().getPortByIndex(0).connectTo(oldDest);
multiplier.getOutputPorts().getPortByIndex(1).connectTo(dest);
} catch (OperatorCreationException e2) {
LogService.getRoot().log(Level.WARNING, "Cannot create multiplier: " + e2.getLocalizedMessage(), e2);
SwingTools.showSimpleErrorMessage("Could not create multiplier",
"Cannot create multiplier: " + e2.getLocalizedMessage());
} finally {
for (Port port : toUnlock) {
port.unlock();
}
}
}
};
JMenuItem menuItem = new JMenuItem(addIOMultiplierActions);
menuItem.setToolTipText(I18N.getGUILabel("cannot_connect.click_to_branch"));
menu.add(menuItem);
// show popup
menu.show(parent, (int) popupLocation.getX(), (int) popupLocation.getY());
ActionListener hideMenuTimer = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (menu.isVisible()) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
menu.setVisible(false);
}
});
}
}
};
final Timer timer = new Timer(HIDE_DELAY, hideMenuTimer);
menuItem.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
super.mouseEntered(e);
timer.stop();
}
@Override
public void mouseExited(MouseEvent e) {
super.mouseExited(e);
timer.start();
}
});
timer.start();
}
}
}