package ui.controller; import classes.AbstractCpsObject; import classes.CpsEdge; import classes.CpsNode; import classes.CpsUpperNode; import classes.Position; import classes.IntermediateCalculationCable; import ui.model.Model; import java.awt.*; import java.util.ArrayList; import java.util.Iterator; class NodeController { private Model model; private CanvasController cvs; private MultiPurposeController mpC; private Point point; NodeController(Model model, CanvasController cvs, MultiPurposeController mpC) { this.model = model; this.cvs = cvs; this.mpC = mpC; } /** * Add a CpsUpperNode into Canvas */ void doUpperNode(String nodeName, CpsUpperNode upperNode, ArrayList toGroup) { CpsUpperNode node = new CpsUpperNode(nodeName); node.setPosition(calculatePos(toGroup)); makeAdjacent(node, upperNode, toGroup); makeNodeOfNodes(node, upperNode, toGroup); backupOldEdges(node, upperNode); if (upperNode == null) cvs.addNewObject(node); else addObjectInUpperNode(node, upperNode, false); } /** * Delete a CpsUpperNode from the Canvas */ void undoUpperNode(CpsUpperNode node, CpsUpperNode upperNode) { Position old = calculatePos(node.getNodes()); Position p = node.getPosition(); point = new Point(old.x - p.x, old.y - p.y); restoreOldEdges(node, upperNode); unmakeNodesOfNodes(node, upperNode); unmakeAdjacent(node, upperNode); if (upperNode == null) cvs.deleteObjectOnCanvas(node); else deleteObjectInUpperNode(node, upperNode); } /** * Put selected Nodes inside the Upper Node */ private void makeNodeOfNodes(CpsUpperNode node, CpsUpperNode upperNode, ArrayList toGroup) { ArrayList nodes = node.getNodes(); ArrayList toDelete = new ArrayList<>(); // Put all selected Nodes into the Upper Node for (AbstractCpsObject obj : toGroup) { // füge Neue Objecte in Neuen Node hinzu addObjectInUpperNode(obj, node, false); } // Füge die Edges die Alle Objekte vorher verbunden hat in neuen Node for (CpsEdge edge : (upperNode == null ? model.getEdgesOnCanvas() : upperNode.getNodeEdges())) { // kopiere edge in UpperNode if (nodes.contains(edge.getA()) && nodes.contains(edge.getB())) { toDelete.add(edge); addEdge(edge, node); } } // Lösche dann die Edges aus der nächst höheren schicht (upperNode == null ? model.getEdgesOnCanvas() : upperNode.getNodeEdges()).removeAll(toDelete); for (AbstractCpsObject abs : toGroup) { if (upperNode == null) removeForNodeOfNode(abs, null); else removeForNodeOfNode(abs, upperNode); } } /** * Transfer all relevant data from Node into the next higher layer of Node * (upperNode) */ private void unmakeNodesOfNodes(CpsUpperNode node, CpsUpperNode upperNode) { // add all nodes into upperNode for (CpsEdge edge : node.getConnections()) { if (edge.getA().equals(node)) edge.getB().getConnections().remove(edge); if (edge.getB().equals(node)) edge.getA().getConnections().remove(edge); } for (AbstractCpsObject obj : node.getNodes()) { updatePosition(obj, upperNode); if (upperNode == null) obj.setSav("CVS"); else obj.setSav("" + upperNode.getId()); } (upperNode == null ? model.getObjectsOnCanvas() : upperNode.getNodes()).addAll(node.getNodes()); // change the indices accordingly the higher layer mpC.adjustIdx(mpC.getHighestIdx((upperNode == null ? model.getCvsObjIdx() : upperNode.getNodesIdx())), node.getNodesIdx()); // add all indices of nodes into upperNode (upperNode == null ? model.getCvsObjIdx() : upperNode.getNodesIdx()).putAll(node.getNodesIdx()); // add all Edges of node into upperNode (upperNode == null ? model.getEdgesOnCanvas() : upperNode.getNodeEdges()).addAll(node.getNodeEdges()); } /** * Look for adjacent Nodes connected with the new CpsUpperNode and make * Connections */ private void makeAdjacent(CpsUpperNode node, CpsUpperNode upperNode, ArrayList toGroup) { ArrayList adj = new ArrayList<>(); ArrayList maxCapacity = new ArrayList<>(); ArrayList oldEdges = node.getOldEdges(); ArrayList toDelete = new ArrayList<>(); // für alle Edges auf dem Canvas for (Iterator it = (upperNode == null ? model.getEdgesOnCanvas() : upperNode.getNodeEdges()) .iterator(); it.hasNext();) { CpsEdge edge = it.next(); // wenn ausgewählte Objekte in edge und andere auserhalb if (toGroup.contains(edge.getA()) && !toGroup.contains(edge.getB())) { // und wenn in der adj noch nicht vorhanden und füg if (!adj.contains(edge.getB())) { adj.add(edge.getB()); maxCapacity.add(edge.getCapacity()); } // wenn vorhanden teste maxCapacity else if (maxCapacity.get(adj.indexOf(edge.getB())) < edge.getCapacity()) { maxCapacity.set(adj.indexOf(edge.getB()), edge.getCapacity()); } // speichere alte edge oldEdges.add(edge); toDelete.add(edge); } // Analog else if (!toGroup.contains(edge.getA()) && toGroup.contains(edge.getB())) { if (!adj.contains(edge.getA())) { adj.add(edge.getA()); maxCapacity.add(edge.getCapacity()); } else if (maxCapacity.get(adj.indexOf(edge.getA())) < edge.getCapacity()) { maxCapacity.set(adj.indexOf(edge.getA()), edge.getCapacity()); } oldEdges.add(edge); toDelete.add(edge); } } (upperNode == null ? model.getEdgesOnCanvas() : upperNode.getNodeEdges()).removeAll(toDelete); } /** * Restore the Old Connections from the adjacent Object */ private void unmakeAdjacent(CpsUpperNode node, CpsUpperNode upperNode) { ArrayList toDelete = new ArrayList<>(); ArrayList lostEdges = new ArrayList<>(); ArrayList foundEdges = (upperNode == null ? model.getEdgesOnCanvas() : upperNode.getNodeEdges()); ArrayList lostChildren = new ArrayList<>(); ArrayList foundChildren = (upperNode == null ? model.getObjectsOnCanvas() : upperNode.getNodes()); // für jede Edge aus upperNode die Node enthält tu sie in toDelete for (CpsEdge edge : foundEdges) { if (edge.getA().equals(node) || edge.getB().equals(node)) toDelete.add(edge); } // mark all object that arent in the restored oldEdges for (CpsEdge edge : node.getOldEdges()) { if (node.getNodes().contains(edge.getA()) && !foundChildren.contains(edge.getB()) && !lostEdges.contains(edge)) { lostChildren.add(edge.getA()); lostEdges.add(edge); } else if (node.getNodes().contains(edge.getB()) && !foundChildren.contains(edge.getA()) && !lostEdges.contains(edge)) { lostChildren.add(edge.getB()); lostEdges.add(edge); } } node.getOldEdges().removeAll(lostEdges); // für alle Edges für die nix passendes gefunden ist for (CpsEdge edge : lostEdges) { AbstractCpsObject toSearch = null; AbstractCpsObject lost = null; boolean foundCps = false; // bestimmung welcher verloren ist und wen man suchen muss if (lostChildren.contains(edge.getA())) { toSearch = edge.getB(); lost = edge.getA(); } else if (lostChildren.contains(edge.getB())) { toSearch = edge.getA(); lost = edge.getB(); } // wenn der zu suchende ein CpsUpperNode war if (toSearch instanceof CpsUpperNode) { System.out.println("UpperNode!"); // guck einfach in den Connections des Verlorenen nach Edges die // auf der Canvas sind. for (CpsEdge e : lost.getConnections()) { if (foundChildren.contains(e.getA()) && foundChildren.contains(e.getB()) && !node.getOldEdges().contains(e) && !foundEdges.contains(e)) { node.getOldEdges().add(e); foundCps = true; } } } // wenn das verlorene Object nicht gefunden if (!foundCps) // für alle auf der Ebene liegende Objekte outerLoop: for (AbstractCpsObject cps : foundChildren) { if (!cps.equals(node) && !lostChildren.contains(cps)) // such per Backtracking Algorithmus ob der enthalten ist if (backtrackLostChild(cps, toSearch, lost)) { // wenns stimmt dann überspringe den aktuellen Loop for (CpsEdge f : node.getOldEdges()) if ((f.getA().equals(cps) && f.getB().equals(toSearch)) || (f.getB().equals(cps) && f.getA().equals(toSearch))) continue outerLoop; // guck nach duplikaten in den Old Edges if (!lookforDuplicates(cps, lost, node.getOldEdges())) { // wenn es keine gibt erzeuge eine neue Oldedge CpsEdge temp = new CpsEdge(cps, lost, edge.getCapacity()); node.getOldEdges().add(temp); } // falls das Objekt ein CpsUpperNode gewesen ist verschiebe // bitte die OldEdge dahin if (cps instanceof CpsUpperNode) { ((CpsUpperNode) cps).getOldEdges().add(edge); } } } } // lösch alle Edges die in toDelete sind und wiederherstell alte Edges (upperNode == null ? model.getEdgesOnCanvas() : upperNode.getNodeEdges()).removeAll(toDelete); (upperNode == null ? model.getEdgesOnCanvas() : upperNode.getNodeEdges()).addAll(node.getOldEdges()); } /** * Just checking if an Egde already exists */ boolean lookforDuplicates(AbstractCpsObject a, AbstractCpsObject b, ArrayList list) { for (CpsEdge cpsEdge : list) { if ((a.equals(cpsEdge.getA()) && b.equals(cpsEdge.getB())) || (b.equals(cpsEdge.getA()) && a.equals(cpsEdge.getB()))) return true; } return false; } /** * Backups Old Edges into next lower layer in Current UpperNode anymore */ private void backupOldEdges(CpsUpperNode node, CpsUpperNode upperNode) { ArrayList backup = new ArrayList<>(); ArrayList adj = new ArrayList<>(); ArrayList maxCapacity = new ArrayList<>(); // wenn upperNode in UpperNode erzeugt wird if (upperNode != null) { // für alle oldEdges die die zu gruppierenden nodes enthält werden // in die neuen upperNOde verschoben for (CpsEdge edge : upperNode.getOldEdges()) { if (!upperNode.getNodes().contains(edge.getA()) && !upperNode.getNodes().contains(edge.getB())) backup.add(edge); } // hier wird verschoben node.getOldEdges().addAll(backup); // neue adjazent muss hergestellt werden in den alten oldEdges // for (CpsEdge edge : upperNode.getOldEdges()) { // // if (node.getNodes().contains(edge.getA())) // if (!adj.contains(edge.getB())) { // adj.add(edge.getB()); // maxCapacity.add(edge.getCapacity()); // } else if (maxCapacity.get(adj.indexOf(edge.getB())) < edge.getCapacity()) { // maxCapacity.set(adj.indexOf(edge.getB()), edge.getCapacity()); // // } // if (node.getNodes().contains(edge.getB())) // if (!adj.contains(edge.getA())) { // adj.add(edge.getA()); // maxCapacity.add(edge.getCapacity()); // } else if (maxCapacity.get(adj.indexOf(edge.getA())) < edge.getCapacity()) { // maxCapacity.set(adj.indexOf(edge.getA()), edge.getCapacity()); // // } // } // alle übertragenen Edges werden gelöscht upperNode.getOldEdges().removeAll(backup); // neue edges werden erzeugt for (AbstractCpsObject cps : adj) upperNode.getOldEdges().add(new CpsEdge(cps, node, maxCapacity.get(adj.indexOf(cps)))); } } /** * Restore Old Edges into next higher layer of UpperNode */ private void restoreOldEdges(CpsUpperNode node, CpsUpperNode upperNode) { ArrayList toDelete = new ArrayList<>(); if (upperNode != null) { for (CpsEdge edge : node.getOldEdges()) { // wenn upperNode weder A oder B von von den OldEdges enthält if (!upperNode.getNodes().contains(edge.getA()) && !upperNode.getNodes().contains(edge.getB())) // Übertrage die OldEdges eine Schicht höher * toDelete.add(edge); } // *übertrage sie hier upperNode.getOldEdges().addAll(toDelete); // lösch sie aus den zu löschenden node, da sonst durch unmake // Adjacent probleme auftauchen node.getOldEdges().removeAll(toDelete); toDelete.clear(); // lösche alle OldEdges aus der höheren schicht die zu den zu // löschenden Node vorher führten for (CpsEdge edge : upperNode.getOldEdges()) { if (edge.getA().equals(node) || edge.getB().equals(node)) toDelete.add(edge); } upperNode.getOldEdges().removeAll(toDelete); } } /** * Calculate new Position of the Upper Node */ Position calculatePos(ArrayList toGroup) { Position pos = new Position(0, 0); // sum(x0 .. xn) / numOfPos, y analog for (AbstractCpsObject abs : toGroup) { pos.x += abs.getPosition().x; pos.y += abs.getPosition().y; } pos.x /= toGroup.size(); pos.y /= toGroup.size(); return pos; } /** * Removes the Given Obj from current Layer and adjusts the idx */ private void removeForNodeOfNode(AbstractCpsObject obj, CpsUpperNode upperNode) { mpC.decIdx(obj.getId(), (upperNode == null ? model.getCvsObjIdx() : upperNode.getNodesIdx())); (upperNode == null ? model.getCvsObjIdx() : upperNode.getNodesIdx()).remove(obj.getId()); (upperNode == null ? model.getObjectsOnCanvas() : upperNode.getNodes()).remove(obj); } /** * Search Lost Nodes by Backtracking by looking for edges * * @param object * actual object which we are looking at * @param find * one part of the Edge * @param lost * other part of the Edge * @return boolean if found */ private boolean backtrackLostChild(AbstractCpsObject object, AbstractCpsObject find, AbstractCpsObject lost) { //if not instance of CpsUpperNode if (!(object instanceof CpsUpperNode)) { //forEach connection look if lost and found inside for (CpsEdge edge : object.getConnections()) { if (edge.getA().equals(find) && edge.getB().equals(lost) || edge.getA().equals(lost) && edge.getB().equals(find)) return true; } return false; } else { //if instance of Uppernode Call again for (AbstractCpsObject cps : ((CpsUpperNode) object).getNodes()) { if (backtrackLostChild(cps, find, lost)) return true; } return false; } } /** * Adds object to the upperNode, might replace objects if replace==true * @param object * @param upperNode * @param replace */ void addObjectInUpperNode(AbstractCpsObject object, CpsUpperNode upperNode, boolean replace) { if(object == null){ new Error("object == null while adding to "+upperNode.toString()).printStackTrace(); return; } if(upperNode == null){ new Error("upperNode == null while adding "+object.toString()).printStackTrace(); return; } object.setSav("" + upperNode.getId()); upperNode.getNodesIdx().put(object.getId(), upperNode.getNodes().size()); upperNode.getNodes().add(object); /** * check if we should drag & drop replace */ if(replace && !(object instanceof CpsNode) ){ /** x of the dragged Object */ int x = object.getPosition().x; /** y of the dragged Object */ int y = object.getPosition().y; /** distance threshold 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 : upperNode.getNodes()){ /** 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) remove it */ if(e.getA() == e.getB()) deleteEdge(e, upperNode); 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()); deleteObjectInUpperNode(toBeReplaced, upperNode); } /** * Add Edge in UpperNode */ void addEdge(CpsEdge edge, CpsUpperNode upperNode) { upperNode.getNodeEdges().add(edge); } /** * Delete Edge in UpperNode */ void deleteEdge(CpsEdge edge, CpsUpperNode upperNode) { edge.getA().getConnections().remove(edge); edge.getB().getConnections().remove(edge); upperNode.getNodeEdges().remove(edge); if (edge.getA() instanceof CpsUpperNode || edge.getB() instanceof CpsUpperNode) cvs.handleUpperNodes(edge); } /** * Connect Objects outside of current Layer to Objects inside the Layer */ void connectNodes(CpsEdge edge, CpsUpperNode upperNode) { // keine Connections nötig, da automatisch erzeugt bei Instanziierung // mache diese Edge auch in OldEdges rein des aktuellen CpsUpperNodes upperNode.getOldEdges().add(edge); } /** * Disconnect Objects outside of current Layer to Objects inside the Layer */ void disconnectNodes(CpsEdge edge, CpsUpperNode upperNode) { edge.getA().getConnections().remove(edge); edge.getB().getConnections().remove(edge); if (upperNode != null) upperNode.getOldEdges().remove(edge); } /** * If Position is out of boundaries adjust it */ private void updatePosition(AbstractCpsObject temp, CpsUpperNode upperNode) { int x = temp.getPosition().x - point.x; int y = temp.getPosition().y - point.y; if (y < 0) y = 0 + model.getScaleDiv2() + 1; if (upperNode != null) { if (x < upperNode.getLeftBorder() + model.getScaleDiv2() + 1) x = upperNode.getLeftBorder() + model.getScaleDiv2() + 1; } else if (x < 0) x = 0 + model.getScaleDiv2() + 1; if (x > model.getCanvasX()) x = model.getCanvasX() - model.getScaleDiv2() - 1; if (y > model.getCanvasX()) y = model.getCanvasY() - model.getScaleDiv2() - 1; temp.setPosition(new Position(x, y)); } }