package ui.controller; import java.awt.Point; import java.util.ArrayDeque; import java.util.ArrayList; import classes.CpsEdge; import classes.CpsNode; import classes.CpsUpperNode; import classes.AbstractCpsObject; import classes.HolonObject; import classes.HolonSwitch; import classes.Position; import interfaces.ObjectListener; import ui.model.Model; /** * Controller for the Canvas. * * @author Gruppe14 */ public class CanvasController { private Model model; private MultiPurposeController mpC; /** * Constructor. * * @param model * the Model * @param mp * the MultipurposeController */ public CanvasController(Model model, MultiPurposeController mp) { this.model = model; this.mpC = mp; } /** * Add an CpsObject to the model and notify the ObjectListener for update. * * @param object * CpsObject to be added. * @param replace when true objects could be replaced */ public void addObject(AbstractCpsObject object, boolean replace) { model.getCvsObjIdx().put(object.getId(), model.getObjectsOnCanvas().size()); model.getObjectsOnCanvas().add(object); /** * check if we should drag & drop replace */ if(!(object instanceof CpsNode) && replace){ /** x of the dragged Object */ int x = object.getPosition().x; /** y of the dragged Object */ int y = object.getPosition().y; /** distance treshold for replacement */ int treshhold = model.getScale()/2; /** number of Objects that might be replaced (should be 1) */ int replaceCounter = 0; /** last object that could be replaced */ AbstractCpsObject toBeReplaced = null; /** for each cps on Canvas */ for (AbstractCpsObject cps : model.getObjectsOnCanvas()){ /** same object -> ignore */ if(cps == object)continue; /** x of object that might get replaced */ int c_x = cps.getPosition().x; /** y of object that might get replaced */ int c_y = cps.getPosition().y; /** if near enough */ if(Math.abs(x-c_x)()); addObject(object, true); } /** * adds the ObjectListener. * * @param objLis * ObjectListener */ public void addObjectListener(ObjectListener objLis) { model.getObjectListeners().add(objLis); } /** * notifies all listeners about changes in the Canvas. */ public void notifyObjListeners() { for (ObjectListener l : model.getObjectListeners()) { l.onChange(model.getObjectsOnCanvas()); } } /** * Deletes an CpsObject on the Canvas and its connections. * * @param obj * AbstractCpsObject */ public void deleteObjectOnCanvas(AbstractCpsObject obj) { CpsEdge e = null; for (AbstractCpsObject cps : model.getObjectsOnCanvas()) { for (CpsEdge p : cps.getConnections()) { if (p.getA() == obj || p.getB() == obj) { e = p; } } if (!model.getClipboradObjects().contains(cps)) { cps.getConnections().remove(e); } model.getEdgesOnCanvas().remove(e); } mpC.decIdx(obj.getId(), model.getCvsObjIdx()); model.getCvsObjIdx().remove(obj.getId()); model.getObjectsOnCanvas().remove(obj); notifyObjListeners(); } /** * Replaces {@code toBeReplaced} by {@code by} on the canvas * @param toBeReplaced the object that will be replaced * @param by the object that will replace it */ public void replaceObjectOnCanvas(AbstractCpsObject toBeReplaced, AbstractCpsObject by) { /** let all edges of 'toBeReplaced' connect to 'by' */ for(CpsEdge e: toBeReplaced.getConnections()){ if(e.getA() == toBeReplaced){ e.setA(by); }else if(e.getB() == toBeReplaced){ e.setB(by); } /** if edge from an object to itself -> remove it */ if(e.getA() == e.getB()) removeEdgesOnCanvas(e); else/** else add edge to 'by' */ by.addConnection(e); } /** delete 'toBeReplaced' new empty connections, to prevent Nullpointer*/ toBeReplaced.setConnections(new ArrayList(1)); /** * set Position of by to exactly toBeReplaced */ by.setPosition(toBeReplaced.getPosition()); deleteObjectOnCanvas(toBeReplaced); } /** * Add an edge to the Canvas. * * @param edge * the edge */ public void addEdgeOnCanvas(CpsEdge edge) { model.getEdgesOnCanvas().add(edge); } /** * Removes an Edge from the Canvas. * * @param edge * the edge to remove */ public void removeEdgesOnCanvas(CpsEdge edge) { edge.getA().getConnections().remove(edge); edge.getB().getConnections().remove(edge); model.getEdgesOnCanvas().remove(edge); if (edge.getA() instanceof CpsUpperNode || edge.getB() instanceof CpsUpperNode) handleUpperNodes(edge); } /** * Paste all Selected Objects. * * @param p * the mouse Position */ public void pasteObjects(Point p) { model.getSelectedCpsObjects().clear(); AbstractCpsObject tCps = null; int x = Integer.MAX_VALUE, y = Integer.MAX_VALUE; // Location whre to copy the Elements for (AbstractCpsObject cps : model.getClipboradObjects()) { if (cps.getPosition().x < x) { x = cps.getPosition().x; } if (cps.getPosition().y < y) { y = cps.getPosition().y; } } ArrayList tempList = new ArrayList<>(); // Objects for (AbstractCpsObject cps : model.getClipboradObjects()) { if (cps instanceof HolonObject) { tCps = new HolonObject((HolonObject) cps); } else if (cps instanceof HolonSwitch) { tCps = new HolonSwitch((HolonSwitch) cps); } else { tCps = new CpsNode("Node"); } tCps.setPosition(new Position(p.x + (cps.getPosition().x - x), p.y + (cps.getPosition().y - y))); tCps.setSav(cps.getSav()); tempList.add(tCps); addObject(tCps, false); // MODEL.getSelectedCpsObjects().add(tCps); } // Edges boolean newEdge = true; for (AbstractCpsObject cps : model.getClipboradObjects()) { for (CpsEdge e : cps.getConnections()) { // A and B of e in the copied Elements? if (model.getClipboradObjects().indexOf(e.getA()) != -1 && model.getClipboradObjects().indexOf(e.getB()) != -1) { AbstractCpsObject a = tempList.get(model.getClipboradObjects().indexOf(e.getA())); AbstractCpsObject b = tempList.get(model.getClipboradObjects().indexOf(e.getB())); // was this Edge created or not? for (CpsEdge et : tempList.get(model.getClipboradObjects().indexOf(cps)).getConnections()) { for (CpsEdge etA : et.getA().getConnections()) { if (et.getA() == a && et.getB() == b) { newEdge = false; } } for (CpsEdge etB : et.getB().getConnections()) { if (et.getA() == a && et.getB() == b) { newEdge = false; } } } if (newEdge) { CpsEdge tempE = new CpsEdge(tempList.get(model.getClipboradObjects().indexOf(e.getA())), // A tempList.get(model.getClipboradObjects().indexOf(e.getB())), /* B */ e.getCapacity()); addEdgeOnCanvas(tempE); } newEdge = true; } } } } /** * Cut all Selected Objects. */ @SuppressWarnings("unchecked") public void cutObjects() { model.setClipboradObjects((ArrayList) model.getSelectedCpsObjects().clone()); for (AbstractCpsObject cps : model.getClipboradObjects()) { deleteObjectOnCanvas(cps); } model.getSelectedCpsObjects().clear(); } /** * In Case if a One or Both Side of the to Removing Edge is a CpsUpperNode * * @param edge * @param upperNode */ public void handleUpperNodes(CpsEdge edge) { CpsUpperNode upper = null; ArrayList toDelete = new ArrayList<>(); // wenn A ist upperNOde if (edge.getA() instanceof CpsUpperNode) { upper = (CpsUpperNode) edge.getA(); // wenn in OldEdges eine B enhält for (CpsEdge cpsEdge : upper.getOldEdges()) { if (cpsEdge.getA().equals(edge.getB()) || cpsEdge.getB().equals(edge.getB())) toDelete.add(cpsEdge); } // lösche alle Edges mit B upper.getOldEdges().removeAll(toDelete); // lösche hier alle Connections for (CpsEdge cpsEdge : toDelete) { cpsEdge.getA().getConnections().remove(cpsEdge); cpsEdge.getB().getConnections().remove(cpsEdge); } toDelete.clear(); } // Hier analog if (edge.getB() instanceof CpsUpperNode) { upper = (CpsUpperNode) edge.getB(); for (CpsEdge cpsEdge : upper.getOldEdges()) { if (cpsEdge.getA().equals(edge.getA()) || cpsEdge.getB().equals(edge.getA())) toDelete.add(cpsEdge); } upper.getOldEdges().removeAll(toDelete); for (CpsEdge cpsEdge : toDelete) { cpsEdge.getA().getConnections().remove(cpsEdge); cpsEdge.getB().getConnections().remove(cpsEdge); } toDelete.clear(); } } /** * Some cleaning Algorithm which traverses the UpperNode through BFS Can be * extended with other cleaning stuff No need for coloring since there tree * is only directed in one direction * * @param node */ public void bfsNodeCleaner(CpsUpperNode node) { ArrayDeque queue = new ArrayDeque<>(); AbstractCpsObject u = node; queue.add(u); while (!queue.isEmpty()) { u = queue.pop(); deleteConnections(u); if (u instanceof CpsUpperNode) for (AbstractCpsObject adjacent : ((CpsUpperNode) u).getNodes()) { queue.add(adjacent); } } } /** * Deletes all Connections to Objects inside the to deleting UpperNode * * @param obj */ private void deleteConnections(AbstractCpsObject obj) { ArrayDeque queue = new ArrayDeque<>(); CpsEdge e = null; for (CpsEdge edge : obj.getConnections()) { queue.add(edge); } while (!queue.isEmpty()) { e = queue.pop(); e.getA().getConnections().remove(e); e.getB().getConnections().remove(e); } } /** * Set the Background Image; * * @param imagePath * Image Path * @param mode * Image Mode * @param width * Image custom width * @param height * Image custom height */ public void setBackgroundImage(String imagePath, int mode, int width, int height) { model.setCanvasImagePath(imagePath); model.setCanvasImageMode(mode); model.setCanvasImageWidth(width); model.setCanvasImageHeight(height); } }