package ui.controller; import classes.*; import classes.IdCounter.CounterType; import com.google.gson.*; import ui.controller.SaveController.EDGETYPE; import ui.controller.SaveController.GRAPHTYPE; import ui.controller.SaveController.NUMTYPE; import ui.controller.SaveController.TYPE; import ui.model.Model; import utility.Vector2Int; import java.awt.*; import java.awt.datatransfer.*; import java.awt.geom.Point2D; import java.io.IOException; import java.util.*; import java.util.List; import java.util.stream.Collectors; public class ClipboardController { private Model model; private SaveController store; private LoadController load; private CanvasController cvsC; private ObjectController objC; private NodeController uppC; private JsonParser parser; private Clipboard clipboard; private HashMap objIDMap; private HashMap eleIDMap; private String sav; private Point point; ClipboardController(Model model, SaveController store, LoadController load, CanvasController cvs, ObjectController obj, NodeController uppC, MultiPurposeController mp) { this.model = model; this.store = store; this.load = load; this.cvsC = cvs; this.objC = obj; this.uppC = uppC; this.clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); parser = new JsonParser(); } /** * Copy marked Objects into Clipboard in Json Format */ public void copy(GroupNode upperNode) { JsonObject file = new JsonObject(); ArrayDeque queue = new ArrayDeque<>(); AbstractCanvasObject u = null; store.initNumeration(); file.add("SAV", new JsonPrimitive((upperNode == null ? "CVS" : "" + upperNode.getId()))); Vector2Int pos = uppC.calculatePos(model.getSelectedCpsObjects()); file.add("CENTER", model.getGson().toJsonTree(pos, Vector2Int.class)); for (AbstractCanvasObject abs : model.getSelectedCpsObjects()) { queue.add(abs); } System.out.println("heiCopy"); while (!queue.isEmpty()) { u = queue.pop(); String key = "CVSOBJECT" + store.getNumerator(NUMTYPE.OBJECT); file.add(key, model.getGson().toJsonTree(u, AbstractCanvasObject.class)); edgeToJson(EDGETYPE.CONNECTION, file, u.getId(), u.getConnections()); if (u instanceof HolonObject) store.elementsToJson(TYPE.CANVAS, file, u); if (u instanceof HolonSwitch) if (((HolonSwitch) u).getGraphPoints().size() != 0) store.unitgraphToJson(GRAPHTYPE.SWITCH, file, u.getId(), ((HolonSwitch) u).getGraphPoints()); if (u instanceof GroupNode) { for (AbstractCanvasObject adjacent : ((GroupNode) u).getNodes()) { queue.add(adjacent); } } } if (upperNode == null) edgeToJson(EDGETYPE.LAYER, file, 0, model.getEdgesOnCanvas()); StringSelection selection = new StringSelection(model.getGson().toJson(file)); clipboard.setContents(selection, selection); } /** * Paste the Copied JsonTree into Canvas */ void paste(GroupNode upperNode, Point p) throws UnsupportedFlavorException, IOException, JsonParseException { if (p == null) return; JsonObject json; Transferable content = clipboard.getContents(null); if (content != null && content.isDataFlavorSupported(DataFlavor.stringFlavor) && !content.isDataFlavorSupported(DataFlavor.allHtmlFlavor)) { String str = (String) content.getTransferData(DataFlavor.stringFlavor); if (parser.parse(str).isJsonObject()) json = (JsonObject) parser.parse(str); else throw new JsonParseException("Unknown Clipboard Information"); } else return; List keys = load.getKeys(json); List edges = keys.stream().filter(key -> key.contains("EDGE")) .collect(Collectors.toCollection(ArrayList::new)); HashMap objDispatch = new HashMap<>(); HashMap eleDispatch = new HashMap<>(); model.getSelectedCpsObjects().clear(); objIDMap = new HashMap<>(); eleIDMap = new HashMap<>(); sav = json.get("SAV").getAsString(); Vector2Int old = model.getGson().getAdapter(Vector2Int.class).fromJsonTree(json.get("CENTER")); point = new Point(old.getX() - p.x, old.getY() - p.y); forwardObjects(keys, json, objDispatch, eleDispatch, upperNode); // for selecting Cps getObjectsInDepth(); forwardEdges(edges, json, objDispatch, upperNode); } /** * Cuts the marked Objects out of Canvas and saves them into the Clipboard */ void cut(GroupNode upperNode) { copy(upperNode); for (AbstractCanvasObject abs : model.getSelectedCpsObjects()) { if (upperNode == null) cvsC.deleteObjectOnCanvas(abs); else uppC.deleteObjectInUpperNode(abs, upperNode); if (abs instanceof GroupNode) cvsC.bfsNodeCleaner((GroupNode) abs); } } private void forwardEdges(List keys, JsonObject json, HashMap objDispatch, GroupNode upperNode) { List conn = new ArrayList<>(); for (String edge : keys) { if (edge.contains("LAYEREDGE")) loadEdge(EDGETYPE.LAYER, json.get(edge), objDispatch, upperNode); if (edge.contains("CONNEDGE")) conn.add(edge); if (edge.contains("NODEEDGE")) loadEdge(EDGETYPE.NODE, json.get(edge), objDispatch, null); if (edge.contains("OLDEDGE")) loadEdge(EDGETYPE.OLD, json.get(edge), objDispatch, null); } for (String edge : conn) { loadEdge(EDGETYPE.CONNECTION, json.get(edge), objDispatch, null); } } private void forwardObjects(List keys, JsonObject json, HashMap objDispatch, HashMap eleDispatch, GroupNode upperNode) { for (String key : keys) { if (key.contains("CVSOBJECT")) loadCanvasObject(json.get(key), objDispatch, upperNode); if (key.contains("CVSELEMENT")) loadCanvasElements(json.get(key), objDispatch, eleDispatch); if (key.contains("SWUNITGRAPH")) loadUnitGraph(GRAPHTYPE.SWITCH, json.get(key), objDispatch, null); if (key.contains("ELEUNITGRAPH")) loadUnitGraph(GRAPHTYPE.ELEMENT, json.get(key), null, eleDispatch); if (key.contains("ELETESTUNITGRAPH")) loadUnitGraph(GRAPHTYPE.TESTELEMENT, json.get(key), null, eleDispatch); } } private void loadCanvasObject(JsonElement jsonElement, HashMap objDispatch, GroupNode upperNode) { AbstractCanvasObject temp = model.getGson().fromJson(jsonElement.getAsJsonObject(), AbstractCanvasObject.class); load.initObjects(temp); objIDMapper(temp); updatePosition(temp, upperNode); // if its stored before on the canvas just put it there if (temp.getSav().equals(sav)) { if (upperNode == null) cvsC.addObject(temp, false); else uppC.addObjectInUpperNode(temp, upperNode, false); // mark the Pasted Objects model.getSelectedCpsObjects().add(temp); } else { // else look up the table and put it into the right Uppernode GroupNode temp2 = (GroupNode) objDispatch.get(objIDMap.get(Integer.parseInt(temp.getSav()))); if(temp2!=null) uppC.addObjectInUpperNode(temp, temp2, false); else{ /** * if corresponding Uppernode doesn't exist: * Add it to the current Canvas/UpperNode */ if (upperNode == null) cvsC.addObject(temp, false); else uppC.addObjectInUpperNode(temp, upperNode, false); } } objDispatch.put(temp.getId(), temp); } private void loadCanvasElements(JsonElement jsonElement, HashMap objDispatch, HashMap eleDispatch) { JsonObject object = jsonElement.getAsJsonObject(); HolonElement temp = model.getGson().fromJson(object.get("properties"), HolonElement.class); load.initElements(temp); eleIDMapper(temp); // id which Object it was stored before int stored = objIDMap.get(object.get("ID").getAsInt()); // lookup that object HolonObject temp2 = (HolonObject) objDispatch.get(stored); // add it objC.addElement(temp2, temp); // store element also inside a table eleDispatch.put(temp.getId(), temp); } private void loadUnitGraph(GRAPHTYPE type, JsonElement jsonElement, HashMap objDispatch, HashMap eleDispatch) { JsonObject object = jsonElement.getAsJsonObject(); List keys = load.getKeys(object); String p; int mid; int sav = 0; LinkedList graphpointTEST = new LinkedList<>(); for (String k : keys) { if (!k.equals("ID")) { p = object.get(k).getAsString(); mid = p.indexOf(':'); double x1 = Double.parseDouble(p.substring(0, mid)); double y1 = Double.parseDouble(p.substring(mid + 1, p.length())); graphpointTEST.add(new Point2D.Double(x1, y1)); } else // else its an ID sav = object.get(k).getAsInt(); } switch (type) { case SWITCH: sav = objIDMap.get(sav); HolonSwitch sw = (HolonSwitch) objDispatch.get(sav); sw.setGraphPoints(graphpointTEST); sw.sampleGraph(); break; case ELEMENT: break; case TESTELEMENT: sav = eleIDMap.get(sav); HolonElement ele1 = eleDispatch.get(sav); ele1.setGraphPoints(graphpointTEST); ele1.sampleGraph(); break; default: break; } } /** * loads an edge from json */ private void loadEdge(EDGETYPE type, JsonElement jsonElement, HashMap objDispatch, GroupNode upperNode) { JsonObject object = jsonElement.getAsJsonObject(); Edge temp = model.getGson().fromJson(object.get("properties"), Edge.class); load.initCpsEdge(temp); // look for A and B inside the Table temp.setA(objDispatch.get(objIDMap.get(object.get("A").getAsInt()))); temp.setB(objDispatch.get(objIDMap.get(object.get("B").getAsInt()))); switch (type) { case LAYER: // if in canvas add it into the canvas but delete connection before model.getEdgesOnCanvas().add(temp); break; case CONNECTION: // if no duplicates in connection store them into the given A and B if (!uppC.lookforDuplicates(temp.getA(), temp.getB(), temp.getA().getConnections())) temp.getA().getConnections().add(temp); if (!uppC.lookforDuplicates(temp.getA(), temp.getB(), temp.getB().getConnections())) temp.getB().getConnections().add(temp); break; default: break; } if (object.get("connection").getAsBoolean() && !type.equals(EDGETYPE.CONNECTION)) { temp.getA().getConnections().add(temp); temp.getB().getConnections().add(temp); } } /** * Modified Method from LoadController. Slightly different */ private void edgeToJson(EDGETYPE type, JsonObject file, int id, ArrayList arr) { String k = null; boolean b = false; JsonObject temp = new JsonObject(); for (Edge edge : arr) { if (model.getClipboradObjects().contains(edge.getA()) && model.getClipboradObjects().contains(edge.getB())) { // add properties and only the ids from a and b temp.add("properties", model.getGson().toJsonTree(edge)); temp.add("A", new JsonPrimitive(edge.getA().getId())); temp.add("B", new JsonPrimitive(edge.getB().getId())); // Key and occasionally the id of Uppernode switch (type) { case LAYER: temp.add("ID", new JsonPrimitive(id)); k = "LAYEREDGE" + store.getNumerator(NUMTYPE.EDGE); break; case CONNECTION: k = "CONNEDGE" + store.getNumerator(NUMTYPE.CONNECTION); break; case NODE: temp.add("ID", new JsonPrimitive(id)); k = "NODEEDGE" + store.getNumerator(NUMTYPE.NODEEDGE); break; case OLD: temp.add("ID", new JsonPrimitive(id)); k = "OLDEDGE" + store.getNumerator(NUMTYPE.OLDEDGE); break; default: break; } // lookup if the CVS, NODE or OLDEDGE are also connections if (edge.getA().getConnections().contains(edge) && edge.getA().getConnections().contains(edge) && !type.equals(EDGETYPE.CONNECTION)) b = true; temp.add("connection", new JsonPrimitive(b)); file.add(k, model.getGson().toJsonTree(temp)); temp = new JsonObject(); } } } /** * Adds all Objects in Depth into Clipboardobjects preemptive when objects are selected */ void getObjectsInDepth() { model.setClipboradObjects(new ArrayList<>()); for (AbstractCanvasObject obj : model.getSelectedCpsObjects()) { clipboadDepth(obj); } } /** * Get all Objects inside the Currentobject and add them into ClipboardObjects */ private void clipboadDepth(AbstractCanvasObject obj) { //modified backtracking Algorithm no True/False if (!(obj instanceof GroupNode)) { model.getClipboradObjects().add(obj); } else { model.getClipboradObjects().add(obj); for (AbstractCanvasObject abs : ((GroupNode) obj).getNodes()) { clipboadDepth(abs); } } } /** * Map the Copied Object ID into a new One */ private void objIDMapper(AbstractCanvasObject temp) { int id = temp.getId(); temp.setId(IdCounter.nextId(CounterType.Object)); // oldID -> currentID objIDMap.put(id, temp.getId()); } /** * Map the Copied Element ID into a new One */ private void eleIDMapper(HolonElement temp) { int id = temp.getId(); temp.setId(IdCounter.nextId(CounterType.Element)); // oldID -> currentID eleIDMap.put(id, temp.getId()); } private void updatePosition(AbstractCanvasObject temp, GroupNode upperNode) { int x = temp.getPosition().getX() - point.x; int y = temp.getPosition().getY() - 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 Vector2Int(x, y)); } }