package pipe.actions.gui; import pipe.controllers.PetriNetController; import pipe.controllers.application.PipeApplicationController; import pipe.controllers.arcCreator.ArcActionCreator; import pipe.gui.PetriNetTab; import pipe.historyActions.component.AddPetriNetObject; import pipe.views.ArcHead; import pipe.views.TemporaryArcView; import uk.ac.imperial.pipe.exceptions.PetriNetComponentException; import uk.ac.imperial.pipe.models.petrinet.*; import uk.ac.imperial.pipe.visitor.connectable.arc.ArcSourceVisitor; import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.util.logging.Level; import java.util.logging.Logger; public final class ArcAction extends CreateAction { /** * Class logger */ private static final Logger LOGGER = Logger.getLogger(ArcAction.class.getName()); /** * Visits the source to determine if we can start the arc type here */ private final ArcSourceVisitor sourceVisitor; private final ArcActionCreator arcCreator; private final PipeApplicationController controller; private final ArcHead arcHead; private TemporaryArcView<? extends Connectable> temporaryArcView = null; public ArcAction(String name, String tooltip, int key, int modifiers, ArcSourceVisitor sourceVisitor, ArcActionCreator arcCreator, PipeApplicationModel applicationModel, PipeApplicationController controller, ArcHead arcHead) { super(name, tooltip, key, modifiers, applicationModel); this.sourceVisitor = sourceVisitor; this.arcCreator = arcCreator; this.controller = controller; this.arcHead = arcHead; } /** * Changes the temporary arc's end point * * @param event mouse event that has just been fired * @param petriNetController current petri net controller for the tab showing */ @Override public void doAction(MouseEvent event, PetriNetController petriNetController) { if (temporaryArcView != null) { temporaryArcView.setEnd(event.getPoint()); if (event.getClickCount() > 0) { Point point = event.getPoint(); temporaryArcView.addIntermediatePoint(new ArcPoint(point, event.isShiftDown())); } PetriNetTab tab = petriNetController.getPetriNetTab(); tab.validate(); tab.repaint(); } } /** * @param connectable the item clicked on * @param petriNetController the controller for the current petrinet */ @Override public <T extends Connectable> void doConnectableAction(T connectable, PetriNetController petriNetController) { PetriNetTab tab = petriNetController.getPetriNetTab(); if (temporaryArcView == null && sourceVisitor.canStart(connectable)) { createTemporaryArc(connectable, tab); } else if (temporaryArcView != null && canCreateArcHere(connectable)) { createArc(connectable, tab); } } /** * @param connectable Source of the temporary arc * @param tab Tab to add TemporaryArc to * @param <T> Source class * @return created Temporary arc */ private <T extends Connectable> void createTemporaryArc(T connectable, final PetriNetTab tab) { temporaryArcView = new TemporaryArcView<>(connectable, arcHead); temporaryArcView.addKeyListener(new ArcViewKeyListener(tab)); tab.add(temporaryArcView); temporaryArcView.requestFocusInWindow(); } private <T extends Connectable> boolean canCreateArcHere(T connectable) { return arcCreator.canCreate(temporaryArcView.getSourceConnectable(), connectable); } private <T extends Connectable> void createArc(T connectable, PetriNetTab tab) { try { ArcCreatorVisitor visitor = new ArcCreatorVisitor(); temporaryArcView.getSourceConnectable().accept(visitor); boolean inbound = visitor.place != null; connectable.accept(visitor); PetriNetController petriNetController = controller.getActivePetriNetController(); PetriNet net = petriNetController.getPetriNet(); Arc<? extends Connectable, ? extends Connectable> arc; if (inbound) { arc = arcCreator.createInboundArc(visitor.place, visitor.transition, temporaryArcView.getIntermediatePoints()); } else { arc = arcCreator.createOutboundArc(visitor.place, visitor.transition, temporaryArcView.getIntermediatePoints()); } registerUndoEvent(new AddPetriNetObject(arc, net)); net.add(arc); } catch (PetriNetComponentException e) { LOGGER.log(Level.SEVERE, e.getMessage()); } tab.remove(temporaryArcView); tab.repaint(); temporaryArcView = null; } /** * Sets place and transition properties accordingly */ private static class ArcCreatorVisitor implements PlaceVisitor, TransitionVisitor { private Place place = null; private Transition transition = null; @Override public void visit(Place place) { this.place = place; } @Override public void visit(Transition transition) { this.transition = transition; } } private final class ArcViewKeyListener implements KeyListener { private final PetriNetTab tab; private ArcViewKeyListener(PetriNetTab tab) { this.tab = tab; } @Override public void keyTyped(KeyEvent e) { //Not needed } @Override public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_META: case KeyEvent.VK_WINDOWS: case KeyEvent.VK_SPACE: tab.setMetaDown(true); break; case KeyEvent.VK_ESCAPE: case KeyEvent.VK_DELETE: tab.remove(temporaryArcView); tab.repaint(); temporaryArcView = null; default: break; } } @Override public void keyReleased(KeyEvent e) { //Not needed } } }