/* * funCKit - functional Circuit Kit * Copyright (C) 2013 Lukas Elsner <open@mindrunner.de> * Copyright (C) 2013 Peter Dahlberg <catdog2@tuxzone.org> * Copyright (C) 2013 Julian Stier <mail@julian-stier.de> * Copyright (C) 2013 Sebastian Vetter <mail@b4sti.eu> * Copyright (C) 2013 Thomas Poxrucker <poxrucker_t@web.de> * Copyright (C) 2013 Alexander Treml <alex.treml@directbox.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.sep2011.funckit.controller; import de.sep2011.funckit.model.graphmodel.AccessPoint; import de.sep2011.funckit.model.graphmodel.Brick; import de.sep2011.funckit.model.graphmodel.Element; import de.sep2011.funckit.model.graphmodel.Input; import de.sep2011.funckit.model.graphmodel.Output; import de.sep2011.funckit.model.graphmodel.Wire; import de.sep2011.funckit.model.graphmodel.implementations.AccessPointImpl; import de.sep2011.funckit.model.graphmodel.implementations.IdPoint; import de.sep2011.funckit.model.graphmodel.implementations.WireImpl; import de.sep2011.funckit.model.graphmodel.implementations.commands.AddBrickCommand; import de.sep2011.funckit.model.graphmodel.implementations.commands.CreateWirePathCommand; import de.sep2011.funckit.model.graphmodel.implementations.commands.SplitWireCommand; import de.sep2011.funckit.model.sessionmodel.EditPanelModel; import de.sep2011.funckit.model.sessionmodel.EditPanelModel.ToolMode; import de.sep2011.funckit.model.sessionmodel.Settings; import de.sep2011.funckit.util.Log; import de.sep2011.funckit.util.command.Command; import de.sep2011.funckit.util.command.CommandDispatcher; import de.sep2011.funckit.util.command.SimpleCommandCombiner; import javax.swing.Timer; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import static de.sep2011.funckit.util.Log.gl; import static javax.swing.SwingUtilities.isLeftMouseButton; import static javax.swing.SwingUtilities.isMiddleMouseButton; import static javax.swing.SwingUtilities.isRightMouseButton; /** * A Tool for drawing Complex Wires. */ public class WireTool extends AbstractTool implements Tool { private List<Point> wirePath = null; private AccessPoint firstClickedAccessPoint = null; private Wire startWire = null; private boolean wasDoubleClick; private CommandDispatcher commandDispatcher; private final List<Command> commandList = new LinkedList<Command>(); private int clickCount; /** * Create a new WireTool. * * @param c * the associated {@link Controller}, should not be null */ public WireTool(Controller c) { assert c != null; this.controller = c; commandDispatcher = controller.getSessionModel().getCurrentGraphCommandDispatcher(); } @Override public WireTool getNewInstance(Controller c) { return new WireTool(c); } private void doubleClick(MouseEvent e, EditPanelModel editPanelModel) { endWirePathCreationFromNull(calculateInversePoint(e.getPoint(), editPanelModel.getTransformation()),editPanelModel); } @Override public void mouseClicked(final MouseEvent e, final EditPanelModel editPanelModel) { clickCount++; final Settings settings = controller.getSessionModel().getSettings(); // only do super double click in default mode if (editPanelModel.getToolMode() == ToolMode.DEFAULT_MODE) { super.mouseClicked(e, editPanelModel); } if (clickCount == 2) { if (editPanelModel.getToolMode() != ToolMode.DEFAULT_MODE) { this.doubleClick(e, editPanelModel); } wasDoubleClick = true; clickCount = 0; } else { Integer timerinterval = 150; Timer timer = new Timer(timerinterval, new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { clickCount = 0; if (wasDoubleClick) { wasDoubleClick = false; // reset flag } else { Point click = calculateInversePoint(e.getPoint(), editPanelModel.getTransformation()); AccessPoint apUnderMouse = editPanelModel.getCircuit() .getAccessPointAtPositon(click, settings.getInt(Settings.ACCESS_POINT_SCATTER_FACTOR)); Wire wireUnderMouse = apUnderMouse == null ? editPanelModel.getCircuit() .getWireAtPosition(click, settings.getInt(Settings.WIRE_SCATTER_FACTOR)) : null; switch (editPanelModel.getToolMode()) { case DEFAULT_MODE: if (apUnderMouse != null && isLeftMouseButton(e)) { startWirePathCreationFromAp(apUnderMouse, editPanelModel); } else if (wireUnderMouse != null && isLeftMouseButton(e)) { startWirePathCreationFromWire(wireUnderMouse, click, editPanelModel); } else if (isLeftMouseButton(e)) { startWirePathCreationFromNull(click, editPanelModel); } break; case CREATE_WIRE_PATH_FROM_WIRE: if (isRightMouseButton(e)) { // cancel on // right click finalizeWirePathCreation(editPanelModel); } else if (isMiddleMouseButton(e)) { if (wireUnderMouse != null) { IdPoint idp = new IdPoint(click); commandList.add(new SplitWireCommand(editPanelModel .getCircuit(), wireUnderMouse, (IdPoint) moveElementForPlacement(idp, false))); endWirePathCreationFromWire(editPanelModel, idp.getOutputO()); } else { endWirePathCreationFromWire(editPanelModel, click); } } else if (wirePath.size() == 1 && click.equals(wirePath.get(0)) && e.getClickCount() == 2) { /* Splits Wire on double click */ commandList.add(new SplitWireCommand(editPanelModel.getCircuit(), startWire, (IdPoint) moveElementForPlacement(new IdPoint( click), false))); finalizeWirePathCreation(editPanelModel); } else if (wireUnderMouse != null) { IdPoint idp = new IdPoint(click); commandList.add(new SplitWireCommand(editPanelModel.getCircuit(), wireUnderMouse, (IdPoint) moveElementForPlacement(idp, false))); endWirePathCreationFromWire(editPanelModel, idp.getOutputO()); } else if (apUnderMouse == null) { wirePath.add(click); updateWirePathGhostsFromWire(editPanelModel, click); } else { endWirePathCreationFromWire(editPanelModel, apUnderMouse); } break; case CREATE_WIRE_PATH_FROM_AP: if (isRightMouseButton(e)) { // cancel on // right click finalizeWirePathCreation(editPanelModel); } else if (isMiddleMouseButton(e)) { if (wireUnderMouse != null) { IdPoint idp = new IdPoint(click); commandList.add(new SplitWireCommand(editPanelModel.getCircuit(), wireUnderMouse, (IdPoint) moveElementForPlacement(idp, false))); endWirePathCreationFromAp(editPanelModel, idp.getOutputO()); } else { endWirePathCreationFromNull(click, editPanelModel); } } else if (wireUnderMouse != null) { IdPoint idp = new IdPoint(click); commandList.add(new SplitWireCommand(editPanelModel.getCircuit(), wireUnderMouse, (IdPoint) moveElementForPlacement(idp, false))); endWirePathCreationFromAp(editPanelModel, idp.getOutputO()); } else if (apUnderMouse == null) { wirePath.add(click); updateWirePathGhostsFromAp(editPanelModel, click); } else { endWirePathCreationFromAp(editPanelModel, apUnderMouse); } break; default: break; } } } }); timer.setRepeats(false); timer.start(); } } private void endWirePathCreationFromNull(Point point, EditPanelModel editPanelModel) { IdPoint idp = new IdPoint(point); commandList.add(new AddBrickCommand(editPanelModel.getCircuit(), firstClickedAccessPoint.getBrick())); commandList.add(new AddBrickCommand(editPanelModel.getCircuit(), (IdPoint) moveElementForPlacement(idp, false))); commandList.add(new CreateWirePathCommand(editPanelModel.getCircuit(), firstClickedAccessPoint, wirePath, idp.getInputA(), true)); finalizeWirePathCreation(editPanelModel); } private void startWirePathCreationFromNull(Point p, EditPanelModel editPanelModel) { wirePath = new LinkedList<Point>(); IdPoint idp = new IdPoint(p); idp = (IdPoint) moveElementForPlacement(idp, false); firstClickedAccessPoint = idp.getOutputO(); editPanelModel.setToolMode(ToolMode.CREATE_WIRE_PATH_FROM_AP); } @Override public void mouseMoved(MouseEvent e, EditPanelModel editPanelModel) { super.mouseMoved(e, editPanelModel); Point click = calculateInversePoint(e.getPoint(), editPanelModel.getTransformation()); switch (editPanelModel.getToolMode()) { case DEFAULT_MODE: // Log.gl().info("def"); break; case CREATE_WIRE_PATH_FROM_AP: // Log.gl().info("ap"); updateWirePathGhostsFromAp(editPanelModel, click); break; case CREATE_WIRE_PATH_FROM_WIRE: // Log.gl().info("wire"); updateWirePathGhostsFromWire(editPanelModel, click); break; default: break; } } public void startWirePathFromCreateTool(AccessPoint ap1, Point p, EditPanelModel editPanelModel) { startWirePathCreationFromAp(ap1, editPanelModel); wirePath.add(p); updateWirePathGhostsFromAp(editPanelModel, p); } private void startWirePathCreationFromAp(AccessPoint startAp, EditPanelModel editPanelModel) { Log.gl().debug("Start Wire Path Creation from AccessPoint"); wirePath = new LinkedList<Point>(); firstClickedAccessPoint = startAp; editPanelModel.setToolMode(ToolMode.CREATE_WIRE_PATH_FROM_AP); } private void startWirePathCreationFromWire(Wire startWire, Point startPoint, EditPanelModel editPanelModel) { Log.gl().debug("Start Wire Path Creation from Wire"); this.startWire = startWire; wirePath = new LinkedList<Point>(); wirePath.add(startPoint); editPanelModel.setToolMode(ToolMode.CREATE_WIRE_PATH_FROM_WIRE); } private void endWirePathCreationFromWire(EditPanelModel editPanelModel, AccessPoint endAccessPoint) { commandList.add(new CreateWirePathCommand(editPanelModel.getCircuit(), startWire, wirePath, endAccessPoint, true)); finalizeWirePathCreation(editPanelModel); } private void endWirePathCreationFromWire(EditPanelModel editPanelModel, Point point) { IdPoint idp = new IdPoint(point); commandList.add(new AddBrickCommand(editPanelModel.getCircuit(), idp)); commandList.add(new CreateWirePathCommand(editPanelModel.getCircuit(), startWire, wirePath, idp.getOutputO(), true)); finalizeWirePathCreation(editPanelModel); } private void finalizeWirePathCreation(EditPanelModel editPanelModel) { commandDispatcher.dispatch(new SimpleCommandCombiner(commandList)); commandList.clear(); clearGhosts(editPanelModel); startWire = null; firstClickedAccessPoint = null; wirePath = null; editPanelModel.setToolMode(ToolMode.DEFAULT_MODE); controller.getSessionModel().restoreTool(); } private void endWirePathCreationFromAp(EditPanelModel editPanelModel, AccessPoint endAccessPoint) { Log.gl().debug("End Wire Path Creation from AccessPoint"); if (!editPanelModel.getCircuit().getElements().contains(firstClickedAccessPoint.getBrick())) { commandList.add(new AddBrickCommand(editPanelModel.getCircuit(), firstClickedAccessPoint.getBrick())); } if (firstClickedAccessPoint instanceof Input) { gl().debug("first: input"); } if (firstClickedAccessPoint instanceof Output) { gl().debug("first: output"); } if (endAccessPoint instanceof Input) { gl().debug("last: input"); } if (endAccessPoint instanceof Output) { gl().debug("last: output"); } commandList.add(new CreateWirePathCommand(editPanelModel.getCircuit(), firstClickedAccessPoint, wirePath, endAccessPoint, true)); finalizeWirePathCreation(editPanelModel); } private void updateWirePathGhostsFromAp(EditPanelModel editPanelModel, Point click) { Brick template = controller.getSessionModel().getCurrentBrick(); /* create a Dummy AccessPoint where the mouse Pointer is */ Brick clickDummyBrick = template.getNewInstance(click); AccessPoint clickDummyAccessPoint = new AccessPointImpl(clickDummyBrick, new Point(0, 0), ""); /* create a Dummy AccessPoint where the start AccessPoint is */ Brick startDummyBrick = template.getNewInstance(new Point(firstClickedAccessPoint .getBrick().getPosition().x + firstClickedAccessPoint.getPosition().x, firstClickedAccessPoint.getBrick().getPosition().y + firstClickedAccessPoint.getPosition().y)); AccessPoint startDummyAccessPoint = new AccessPointImpl(startDummyBrick, new Point(0, 0), ""); Set<Element> ghosts = new LinkedHashSet<Element>(); if (wirePath.isEmpty()) { Wire ghostWire = new WireImpl(startDummyAccessPoint, clickDummyAccessPoint); ghosts.add(ghostWire); } else { IdPoint idp = new IdPoint(wirePath.get(0)); idp = (IdPoint) moveElementForPlacement(idp, false); AccessPoint ap = idp.getInputA(); Wire ghostWire = new WireImpl(startDummyAccessPoint, ap); ghosts.add(ghostWire); List<IdPoint> idPointPath = new ArrayList<IdPoint>(wirePath.size()); ghosts.addAll(getGhosts(wirePath, idPointPath)); ghosts.add(new WireImpl(idPointPath.get(idPointPath.size() - 1).getOutputO(), clickDummyAccessPoint)); } editPanelModel.setGhosts(ghosts); } private void updateWirePathGhostsFromWire(EditPanelModel editPanelModel, Point click) { Brick template = controller.getSessionModel().getCurrentBrick(); /* create a Dummy AccessPoint where the mouse Pointer is */ Brick clickDummyBrick = template.getNewInstance(click); AccessPoint clickDummyAccessPoint = new AccessPointImpl(clickDummyBrick, new Point(0, 0), ""); List<IdPoint> idPointPath = new ArrayList<IdPoint>(wirePath.size()); Set<Element> ghosts = getGhosts(wirePath, idPointPath); ghosts.add(new WireImpl(idPointPath.get(idPointPath.size() - 1).getOutputO(), clickDummyAccessPoint)); editPanelModel.setGhosts(ghosts); } private Set<Element> getGhosts(List<Point> wirePath, List<IdPoint> idPointPath) { Set<Element> ghosts = new LinkedHashSet<Element>(); for (Point p : wirePath) { IdPoint idp = new IdPoint(p); idPointPath.add(idp); /* Move IdPoints to center */ moveElementForPlacement(idp, false); ghosts.add(idp); } for (int i = 0; i < idPointPath.size() - 1; i++) { IdPoint idp1 = idPointPath.get(i); IdPoint idp2 = idPointPath.get(i + 1); Wire ghostWire2 = new WireImpl(idp1.getOutputO(), idp2.getInputA()); ghosts.add(ghostWire2); } return ghosts; } @Override public void mouseExited(MouseEvent mouseEvent, EditPanelModel editPanelModel) { super.mouseExited(mouseEvent, editPanelModel); } @Override protected void cancelCurrentAction(EditPanelModel editPanelModel) { finalizeWirePathCreation(editPanelModel); } }