package ui.controller; import java.awt.Color; import java.awt.Point; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.stream.Collectors; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonIOException; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSyntaxException; import com.google.gson.stream.JsonReader; import com.google.gson.stream.MalformedJsonException; import TypeAdapter.AbstractCpsObjectAdapter; import TypeAdapter.ColorAdapter; import TypeAdapter.PositionAdapter; import classes.AbstractCpsObject; import classes.CpsEdge; import classes.CpsUpperNode; import classes.HolonElement; import classes.HolonObject; import classes.HolonSwitch; import classes.IdCounter; import classes.IdCounterElem; import classes.Position; import ui.controller.StoreController.EDGETYPE; import ui.controller.StoreController.GRAPHTYPE; import ui.controller.StoreController.NUMTYPE; import ui.controller.StoreController.TYPE; import ui.model.Model; import ui.view.UpperNodeCanvas; public class ClipboardController { private Model model; private StoreController store; private LoadController load; private CanvasController cvsC; private ObjectController objC; private NodeController uppC; private MultiPurposeController mpC; private Gson gson; private JsonParser parser; private Clipboard clipboard; private HashMap objIDMap; private HashMap eleIDMap; private String sav; private Point point; private Point pp; public ClipboardController(Model model, StoreController 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.mpC = mp; this.clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); initGson(); } /** * * @param upperNode */ public void copy(CpsUpperNode upperNode) { JsonObject file = new JsonObject(); ArrayDeque queue = new ArrayDeque<>(); AbstractCpsObject u = null; store.initNumeration(); file.add("SAV", new JsonPrimitive((upperNode == null ? "CVS" : "" + upperNode.getId()))); Position pos = uppC.calculatePos(model.getSelectedCpsObjects()); file.add("CENTER", gson.toJsonTree(pos, Position.class)); for (AbstractCpsObject abs : model.getSelectedCpsObjects()) { queue.add(abs); } while (!queue.isEmpty()) { u = queue.pop(); String key = "CVSOBJECT" + store.getNumerator(NUMTYPE.OBJECT); file.add(key, gson.toJsonTree(u, AbstractCpsObject.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 CpsUpperNode) { for (AbstractCpsObject adjacent : ((CpsUpperNode) u).getNodes()) { queue.add(adjacent); } edgeToJson(EDGETYPE.NODE, file, u.getId(), ((CpsUpperNode) u).getNodeEdges()); edgeToJson(EDGETYPE.OLD, file, u.getId(), ((CpsUpperNode) u).getOldEdges()); } } if (upperNode == null) edgeToJson(EDGETYPE.LAYER, file, 0, model.getEdgesOnCanvas()); else edgeToJson(EDGETYPE.LAYER, file, upperNode.getId(), upperNode.getNodeEdges()); StringSelection selection = new StringSelection(gson.toJson(file)); clipboard.setContents(selection, selection); } /** * * @param upperNode */ public void paste(CpsUpperNode upperNode, Point p) throws UnsupportedFlavorException, IOException, JsonParseException { if (p == null) return; JsonObject json = new JsonObject(); 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(); Position old = gson.getAdapter(Position.class).fromJsonTree(json.get("CENTER")); point = new Point(old.x - p.x, old.y - p.y); forwardObjects(keys, json, objDispatch, eleDispatch, upperNode); // for selecting Cps getObjectsInDepth(); forwardEdges(edges, json, objDispatch, upperNode); } public void cut(CpsUpperNode upperNode) { copy(upperNode); ArrayList found = (upperNode == null ? model.getObjectsOnCanvas() : upperNode.getNodes()); for (AbstractCpsObject abs : model.getSelectedCpsObjects()) { if (upperNode == null) cvsC.deleteObjectOnCanvas(abs); else uppC.deleteObjectInUpperNode(abs, upperNode); if (abs instanceof CpsUpperNode) cvsC.bfsNodeCleaner((CpsUpperNode) abs); } } private void forwardEdges(List keys, JsonObject json, HashMap objDispatch, CpsUpperNode upperNode) { // TODO Auto-generated method stub 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, CpsUpperNode upperNode) { // TODO Auto-generated method stub 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); } } private void loadCanvasObject(JsonElement jsonElement, HashMap objDispatch, CpsUpperNode upperNode) { // TODO Auto-generated method stub AbstractCpsObject temp = gson.fromJson(jsonElement.getAsJsonObject(), AbstractCpsObject.class); load.initObjects(temp); objIDMapper(temp); updatePosition(temp); // if its stored before on the canvas just put it there if (temp.getSav().equals(sav)) { if (upperNode == null) cvsC.addObject(temp); else uppC.addObjectInUpperNode(temp, upperNode); // mark the Pasted Objects model.getSelectedCpsObjects().add(temp); } else { // else look up the table and put it into the right Uppernode CpsUpperNode temp2 = (CpsUpperNode) objDispatch.get(objIDMap.get(Integer.parseInt(temp.getSav()))); uppC.addObjectInUpperNode(temp, temp2); } objDispatch.put(temp.getId(), temp); } private void loadCanvasElements(JsonElement jsonElement, HashMap objDispatch, HashMap eleDispatch) { // TODO Auto-generated method stub JsonObject object = jsonElement.getAsJsonObject(); HolonElement temp = gson.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) { // TODO Auto-generated method stub JsonObject object = jsonElement.getAsJsonObject(); List keys = load.getKeys(object); String p = null; int mid, x, y = 0; LinkedList graphpoint = new LinkedList<>(); int sav = 0; // foreach Point in the graph restore it for (String k : keys) { if (!k.equals("ID")) { p = object.get(k).getAsString(); mid = p.indexOf(':'); x = Integer.parseInt(p.substring(0, mid)); y = Integer.parseInt(p.substring(mid + 1, p.length())); graphpoint.add(new Point(x, y)); } 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(graphpoint); break; case ELEMENT: sav = eleIDMap.get(sav); HolonElement ele = eleDispatch.get(sav); ele.setGraphPoints(graphpoint); break; default: break; } } private void loadEdge(EDGETYPE type, JsonElement jsonElement, HashMap objDispatch, CpsUpperNode upperNode) { // TODO Auto-generated method stub JsonObject object = jsonElement.getAsJsonObject(); CpsEdge temp = gson.fromJson(object.get("properties"), CpsEdge.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()))); int sav = 0; switch (type) { case LAYER: // if in canvas add it into the canvas but delete connection before (upperNode == null ? model.getEdgesOnCanvas() : upperNode.getNodeEdges()).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; case NODE: // put it into given nodeofnode sav = objIDMap.get(object.get("ID").getAsInt()); ((CpsUpperNode) objDispatch.get(sav)).getNodeEdges().add(temp); break; case OLD: // same as above sav = objIDMap.get(object.get("ID").getAsInt()); ((CpsUpperNode) objDispatch.get(sav)).getOldEdges().add(temp); break; default: break; } if (object.get("connection").getAsBoolean() && !type.equals(EDGETYPE.CONNECTION)) { temp.getA().getConnections().add(temp); temp.getB().getConnections().add(temp); } } /** * * @param type * @param file * @param id * @param arr */ private void edgeToJson(EDGETYPE type, JsonObject file, int id, ArrayList arr) { // TODO Auto-generated method stub String k = null; boolean b = false; JsonObject temp = new JsonObject(); for (CpsEdge 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", gson.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, gson.toJsonTree(temp)); temp = new JsonObject(); } } } /** * */ public void getObjectsInDepth() { model.setClipboradObjects(new ArrayList<>()); for (AbstractCpsObject obj : model.getSelectedCpsObjects()) { clipboadDepth(obj); } } /** * * @param obj */ private void clipboadDepth(AbstractCpsObject obj) { if (!(obj instanceof CpsUpperNode)) { model.getClipboradObjects().add(obj); return; } else { model.getClipboradObjects().add(obj); for (AbstractCpsObject abs : ((CpsUpperNode) obj).getNodes()) { clipboadDepth(abs); } return; } } private void initGson() { // TODO Auto-generated method stub GsonBuilder builder = new GsonBuilder(); builder.excludeFieldsWithoutExposeAnnotation().serializeNulls().setPrettyPrinting(); builder.registerTypeAdapter(AbstractCpsObject.class, new AbstractCpsObjectAdapter()); builder.registerTypeAdapter(Position.class, new PositionAdapter()); builder.registerTypeAdapter(Color.class, new ColorAdapter()); // use the builder and make a instance of the Gson this.gson = builder.create(); this.parser = new JsonParser(); } private void objIDMapper(AbstractCpsObject temp) { // TODO Auto-generated method stub int id = temp.getId(); temp.setId(IdCounter.nextId()); objIDMap.put(id, temp.getId()); } private void eleIDMapper(HolonElement temp) { // TODO Auto-generated method stub int id = temp.getId(); temp.setId(IdCounterElem.nextId()); eleIDMap.put(id, temp.getId()); } private void updatePosition(AbstractCpsObject temp) { // TODO Auto-generated method stub int x = temp.getPosition().x - point.x; int y = temp.getPosition().y - point.y; if(x < 0) x = 0; if(x > model.getCanvasX()) x = model.getCanvasX(); if(y < 0) y = 0; if(y > model.getCanvasX()) y = model.getCanvasY(); temp.setPosition(new Position(x, y)); } }