Browse Source

fixes #82: saving of the position works only on clean exit (with exit-dialog)

I. Dix 6 years ago
parent
commit
3af096cd0d

+ 17 - 0
src/ui/controller/Control.java

@@ -41,6 +41,8 @@ public class Control {
     private SimulationManager simulationManager;
     private String autosaveDir = "";
     private String categoryDir = "";
+    private String otherDir = "";
+    private String dimensionsFileName = "dimensions";
     private int rand;
 
     /**
@@ -70,11 +72,14 @@ public class Control {
 
         autosaveDir = System.getProperty("user.home") + "/.config/HolonGUI/Autosave/";
         categoryDir = System.getProperty("user.home") + "/.config/HolonGUI/Category/";
+        otherDir = System.getProperty("user.home") + "/.config/HolonGUI/Other/";
         File autoSave = new File(autosaveDir);
         File category = new File(categoryDir);
+        File other = new File(otherDir);
         // deleteDirectory(dest);
         autoSave.mkdirs();
         category.mkdirs();
+        other.mkdirs();
         createAutoRandom();
         try {
             autoSave();
@@ -477,6 +482,14 @@ public class Control {
         loadController.readJson(path);
     }
 
+    public ArrayList<Integer> loadSavedWindowDimensionsIfExistent() {
+        try {
+            return loadController.readWindowDimensions(otherDir + dimensionsFileName);
+        } catch (Exception e) {
+            return new ArrayList<>();
+        }
+    }
+
     /**
      * Init the CategoryListener.
      *
@@ -567,6 +580,10 @@ public class Control {
         saveController.writeCategory(categoryDir + "Category.json");
     }
 
+    public void savePosAndSizeOfWindow(int x, int y, int width, int height) throws IOException, ArchiveException {
+        saveController.writeWindowStatus(otherDir + dimensionsFileName, x, y, width, height);
+    }
+
     /**
      * Returns the undo save.
      *

+ 19 - 1
src/ui/controller/LoadController.java

@@ -73,6 +73,23 @@ public class LoadController {
 
     }
 
+    /**
+     * reads the dimensions file containing the saved position and dimensions of the frame
+     *
+     * @return a list of the form [x, y, width, height]
+     */
+    ArrayList<Integer> readWindowDimensions(String path) throws FileNotFoundException {
+        JsonObject json = (JsonObject) parser.parse(new FileReader(path));
+        ArrayList<Integer> dimensions = new ArrayList<>();
+
+        List<String> keys = getKeys(json);
+        for (int i = 1; i < 5; i++) {
+            dimensions.add(json.get(keys.get(i)).getAsInt());
+        }
+
+        return dimensions;
+    }
+
     void readJson(String path) throws IOException {
         JsonObject json = (JsonObject) parser.parse(new FileReader(path));
         // get all keys via stream
@@ -502,7 +519,8 @@ public class LoadController {
     }
 
     /**
-     * enum Mode.
+     * enum Mode. (in SaveController there is an additional mode called SIZE,
+     * it is not currently needed here and was therefore not added)
      */
     public enum MODE {
         COMPLETE, PARTIAL, CATEGORY

+ 477 - 456
src/ui/controller/SaveController.java

@@ -17,465 +17,486 @@ import java.util.List;
 
 /**
  * Controller for Storage.
- * 
+ *
  * @author Gruppe14
  */
 public class SaveController {
 
-	private Model model;
-	private int nCat, nObj, nEle, nEdge, nConn, nNodeEdge, nOldEdge, nUnitGraph, nStatsGraph;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param model
-	 *            the Model
-	 */
-	SaveController(Model model) {
-		this.model = model;
-	}
-
-	/**
-	 * Writes the current State of the Modelling into a JSON File which can be
-	 * loaded.
-	 *
-	 * @param path
-	 *            the Path
-	 *
-	 * @throws IOException
-	 *             exception
-	 */
-	void writeSave(String path) throws IOException, ArchiveException {
-
-		File dst = new File(path);
-		File holonFile = File.createTempFile("tmp", ".json");
-		holonFile.deleteOnExit();
-		dst.delete();
-
-		OutputStream output = new FileOutputStream(dst);
-		ArchiveOutputStream stream = new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.ZIP,
-				output);
-
-		initNumeration();
-		JsonObject file = new JsonObject();
-		initialize(MODE.COMPLETE, file);
-		storeCategory(file);
-		storeCanvas(file);
-		storeStatistics(file);
-		storeData(stream);
-
-		FileWriter writer = new FileWriter(holonFile);
-		writer.write(model.getGson().toJson(file));
-		writer.flush();
-		writer.close();
-
-		addFileToSave(holonFile, stream, false);
-
-		stream.finish();
-		output.close();
-
-	}
-
-	/**
-	 * Writes the Autosave File.
-	 *
-	 * @param path
-	 *            the Path
-	 * @throws IOException
-	 *             Exception
-	 */
-	void writeAutosave(String path) throws IOException {
-
-		initNumeration();
-		JsonObject file = new JsonObject();
-		initialize(MODE.PARTIAL, file);
-		storeCanvas(file);
-
-		FileWriter writer = new FileWriter(path);
-		writer.write(model.getGson().toJson(file));
-
-		writer.flush();
-		writer.close();
-	}
-
-	/**
-	 * Writes the Category File in Case of Changes
-	 */
-	void writeCategory(String path) throws IOException {
-
-		initNumeration();
-		JsonObject file = new JsonObject();
-		initialize(MODE.CATEGORY, file);
-		storeCategory(file);
-
-		FileWriter writer = new FileWriter(path);
-		writer.write(model.getGson().toJson(file));
-
-		writer.flush();
-		writer.close();
-
-	}
-
-	/**
-	 * Write needed default parameter into the JsonObject. Can be extended later
-	 * on
-	 */
-	private void initialize(MODE mode, JsonObject file) {
-		switch (mode) {
-		case COMPLETE:
-			file.add("MODE", new JsonPrimitive(mode.name()));
-			file.add("IDCOUNTER", new JsonPrimitive(IdCounter.getCounter()));
-			file.add("IDCOUNTERELEMENT", new JsonPrimitive(IdCounterElem.getCounter()));
-			file.add("CANVAS_SIZE_X", new JsonPrimitive(model.getCanvasX()));
-			file.add("CANVAS_SIZE_Y", new JsonPrimitive(model.getCanvasY()));
-			break;
-		case PARTIAL:
-			file.add("MODE", new JsonPrimitive(mode.name()));
-			file.add("IDCOUNTER", new JsonPrimitive(IdCounter.getCounter()));
-			file.add("IDCOUNTERELEMENT", new JsonPrimitive(IdCounterElem.getCounter()));
-			file.add("CANVAS_SIZE_X", new JsonPrimitive(model.getCanvasX()));
-			file.add("CANVAS_SIZE_Y", new JsonPrimitive(model.getCanvasY()));
-			break;
-		case CATEGORY:
-			file.add("MODE", new JsonPrimitive(mode.name()));
-		default:
-			break;
-		}
-
-	}
-
-	/**
-	 * Store all Categories and Object into a Json File via Serialization
-	 */
-	private void storeCategory(JsonObject file) {
-		// forall categories store them into the jsontree
-		for (Category cat : model.getCategories()) {
-			String key = "CATEGORY" + getNumerator(NUMTYPE.CATEGORY);
-
-			file.add(key, new JsonPrimitive(cat.getName()));
-			// forall object in the category store them into the jsontree
-			for (AbstractCpsObject obj : cat.getObjects()) {
-				file.add("CGOBJECT" + getNumerator(NUMTYPE.OBJECT),
-						model.getGson().toJsonTree(obj, AbstractCpsObject.class));
-				// if its a holonobject add elements too
-				if (obj instanceof HolonObject)
-					elementsToJson(TYPE.CATEGORY, file, obj);
-			}
-		}
-	}
-
-	/**
-	 * Travers through all Objects via BFS and Stores everything relevant
-	 */
-	private void storeCanvas(JsonObject file) {
-		ArrayDeque<AbstractCpsObject> queue = new ArrayDeque<>();
-		AbstractCpsObject u = null;
-		// put all objects into queue since there is not starting object
-		for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
-			queue.add(cps);
-		}
-		// while quene not empty
-		while (!queue.isEmpty()) {
-
-			// u = current node
-			u = queue.pop();
-			// add currentnode into jsontree
-			String key = "CVSOBJECT" + getNumerator(NUMTYPE.OBJECT);
-			file.add(key, model.getGson().toJsonTree(u, AbstractCpsObject.class));
-			// and its connections too
-			edgeToJson(EDGETYPE.CONNECTION, file, u.getId(), u.getConnections());
-			// if holonobject elements too
-			if (u instanceof HolonObject)
-				elementsToJson(TYPE.CANVAS, file, u);
-			// if switch graphpoints too
-			if (u instanceof HolonSwitch)
-				if (((HolonSwitch) u).getGraphPoints().size() != 0)
-					unitgraphToJson(GRAPHTYPE.SWITCH, file, u.getId(), ((HolonSwitch) u).getGraphPoints());
-			// if uppernode put all nodes inside the uppernode into queue
-			if (u instanceof CpsUpperNode) {
-				for (AbstractCpsObject adjacent : ((CpsUpperNode) u).getNodes()) {
-					queue.add(adjacent);
-				}
-				// dont forget to add the nodeedges and oldedges
-				edgeToJson(EDGETYPE.NODE, file, u.getId(), ((CpsUpperNode) u).getNodeEdges());
-				edgeToJson(EDGETYPE.OLD, file, u.getId(), ((CpsUpperNode) u).getOldEdges());
-			}
-		}
-		// lastly add canvasedges into json
-		edgeToJson(EDGETYPE.CANVAS, file, 0, model.getEdgesOnCanvas());
-
-	}
-
-	private void storeStatistics(JsonObject file) {
-		trackedToJson(file);
-		statisticgraphToJson(file);
-	}
-
-	/**
-	 * Save wanted Data
-	 */
-	private void storeData(ArchiveOutputStream stream) throws IOException {
-		File images = new File(System.getProperty("user.home") + "/.config/HolonGUI/Images");
-		File background = new File(System.getProperty("user.home") + "/.config/HolonGUI/BackgroundImages");
-		addFilesToSave(images, stream);
-		addFilesToSave(background, stream);
-
-	}
-
-	/**
-	 * Stores Category or Canvas Elements into Json
-	 */
-	void elementsToJson(TYPE type, JsonObject file, AbstractCpsObject obj) {
-		JsonObject temp = new JsonObject();
-		String key = null;
-		// forall elements store them into json and include the id of the object
-		for (HolonElement ele : ((HolonObject) obj).getElements()) {
-			temp.add("properties", model.getGson().toJsonTree(ele));
-			temp.add("ID", new JsonPrimitive(obj.getId()));
-			// switch for deciding the key
-			switch (type) {
-			case CANVAS:
-				key = "CVSELEMENT" + getNumerator(NUMTYPE.ELEMENT);
-				break;
-			case CATEGORY:
-				key = "CGELEMENT" + getNumerator(NUMTYPE.ELEMENT);
-				break;
-			default:
-				break;
-			}
-			file.add(key, model.getGson().toJsonTree(temp));
-			// if there are gps add them into
-			if (ele.getGraphPoints().size() != 0)
-				unitgraphToJson(GRAPHTYPE.ELEMENT, file, ele.getId(), ele.getGraphPoints());
-			temp = new JsonObject();
-		}
-
-	}
-
-	/**
-	 * Put the UnitGraphs of Switches or Elements into Json
-	 */
-	void unitgraphToJson(GRAPHTYPE type, JsonObject file, int id, LinkedList<Point> graph) {
-
-		JsonObject temp = new JsonObject();
-		String key = null;
-		// forall points add them
-		for (int i = 0; i < graph.size(); i++) {
-			temp.add("" + i, new JsonPrimitive(graph.get(i).x + ":" + graph.get(i).y));
-		}
-		// decide key
-		switch (type) {
-		case SWITCH:
-			key = "SWUNITGRAPH" + getNumerator(NUMTYPE.UNITGRAPH);
-			break;
-		case ELEMENT:
-			key = "ELEUNITGRAPH" + getNumerator(NUMTYPE.UNITGRAPH);
-			break;
-		default:
-			break;
-		}
-		// add id of element so it can be found again
-		temp.add("ID", new JsonPrimitive(id));
-
-		file.add(key, model.getGson().toJsonTree(temp));
-	}
-
-	/**
-	 * Canvas-Edge, Connections, Node-Edge and Old-Edges to json
-	 */
-	private void edgeToJson(EDGETYPE type, JsonObject file, int id, ArrayList<CpsEdge> arr) {
-		String k = null;
-		boolean b = false;
-		JsonObject temp = new JsonObject();
-
-		for (CpsEdge edge : arr) {
-			// 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 CANVAS:
-				k = "CVSEDGE" + getNumerator(NUMTYPE.EDGE);
-				break;
-			case CONNECTION:
-				k = "CONNEDGE" + getNumerator(NUMTYPE.CONNECTION);
-				break;
-			case NODE:
-				temp.add("ID", new JsonPrimitive(id));
-				k = "NODEEDGE" + getNumerator(NUMTYPE.NODEEDGE);
-				break;
-			case OLD:
-				temp.add("ID", new JsonPrimitive(id));
-				k = "OLDEDGE" + 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();
-		}
-
-	}
-
-	private void trackedToJson(JsonObject file) {
-		JsonObject temp = new JsonObject();
-		String key = "TRACKED";
-		// forall points add them
-		for (int i = 0; i < model.getTrackingObj().size(); i++) {
-			temp.add("" + i, new JsonPrimitive(model.getTrackingObj().get(i).getId()));
-		}
-
-		file.add(key, model.getGson().toJsonTree(temp));
-	}
-
-	private void statisticgraphToJson(JsonObject file) {
-		JsonObject temp = new JsonObject();
-
-		List<String> keys = new ArrayList<>(model.getGraphTable().keySet());
-
-		for (String k : keys) {
-			JsonObject dataSet = new JsonObject();
-			for (int i = 0; i < model.getGraphTable().get(k).getStatGraph().getDataSets().size(); i++) {
-				TrackedDataSet set = model.getGraphTable().get(k).getStatGraph().getDataSets().get(i);
-				AbstractCpsObject cps = set.getCpsObject();
-
-				dataSet.add("ID", (cps == null ? null : new JsonPrimitive(cps.getId())));
-				dataSet.add("COLOR", model.getGson().toJsonTree(set.getColor(), Color.class));
-				dataSet.add("PROPERTY", new JsonPrimitive(set.getProperty()));
-				temp.add("" + i, model.getGson().toJsonTree(dataSet));
-				dataSet = new JsonObject();
-			}
-			temp.add("KEY", new JsonPrimitive(k));
-
-			file.add("STATSGRAPH" + getNumerator(NUMTYPE.STATSGRAPH), model.getGson().toJsonTree(temp));
-			temp = new JsonObject();
-		}
-
-	}
-
-	/**
-	 * Differs Between Single file or whole Directory to Store
-	 */
-	private void addFilesToSave(File src, ArchiveOutputStream stream) throws IOException {
-		if (!src.exists())
-			return;
-
-		ArrayList<File> files = new ArrayList<>();
-		files.addAll(Arrays.asList(src.listFiles()));
-
-		for (File file : files) {
-			if (file.isDirectory())
-				addFilesToSave(file, stream);
-			else
-				addFileToSave(file, stream, true);
-		}
-
-	}
-
-	/**
-	 * Add a File into the Archive
-	 */
-	private void addFileToSave(File src, ArchiveOutputStream stream, boolean dir) throws IOException {
-		String entryName = (dir ? src.getCanonicalPath() : src.getName());
-
-		entryName = checkOS(entryName);
-
-		ZipArchiveEntry entry = new ZipArchiveEntry(entryName);
-		stream.putArchiveEntry(entry);
-		BufferedInputStream input = new BufferedInputStream(new FileInputStream(src));
-
-		IOUtils.copy(input, stream);
-		input.close();
-		stream.closeArchiveEntry();
-	}
-
-	private String checkOS(String entryName) {
-		String os = System.getProperty("os.name").toLowerCase();
-		String ret = entryName;
-		String partition = null;
-
-		if (os.contains("windows")) {
-			partition = ret.substring(0, ret.indexOf(":") + 1);
-			ret = ret.replace(System.getProperty("user.home") + "\\.config\\HolonGUI\\", "");
-			ret = ret.replace(partition, "");
-		}
-		if (os.contains("mac")) {
-			// dosmth
-			ret = ret.replace(System.getProperty("user.home") + "/.config/HolonGUI/", "");
-		}
-		if (os.contains("linux")) {
-			// dosmth
-			ret = ret.replace(System.getProperty("user.home") + "/.config/HolonGUI/", "");
-		}
-		if (os.contains("solaris")) {
-			// dosmth
-		}
-		return ret;
-	}
-
-	/**
-	 * Just initialize the Numerators for the Json Keys. Maybe bad Style..
-	 */
-	void initNumeration() {
-		this.nCat = this.nObj = this.nEle = this.nEdge = this.nConn = this.nNodeEdge = this.nOldEdge = this.nStatsGraph = 0;
-	}
-
-	/**
-	 * Get the wanted numerator and increment it
-	 */
-	int getNumerator(NUMTYPE type) {
-
-		switch (type) {
-		case CATEGORY:
-			return nCat++;
-		case OBJECT:
-			return nObj++;
-		case ELEMENT:
-			return nEle++;
-		case EDGE:
-			return nEdge++;
-		case CONNECTION:
-			return nConn++;
-		case NODEEDGE:
-			return nNodeEdge++;
-		case OLDEDGE:
-			return nOldEdge++;
-		case UNITGRAPH:
-			return nUnitGraph++;
-		case STATSGRAPH:
-			return nStatsGraph++;
-
-		default:
-			break;
-		}
-		return -1;
-	}
-
-	public enum MODE {
-		COMPLETE, PARTIAL, CATEGORY
-	}
-
-	public enum TYPE {
-		CATEGORY, CANVAS
-	}
-
-	public enum EDGETYPE {
-		CANVAS, CONNECTION, NODE, OLD, LAYER
-	}
-
-	public enum NUMTYPE {
-		CATEGORY, OBJECT, ELEMENT, EDGE, CONNECTION, NODEEDGE, OLDEDGE, UNITGRAPH, STATSGRAPH
-	}
-
-	public enum GRAPHTYPE {
-		SWITCH, ELEMENT
-	}
+    private Model model;
+    private int nCat, nObj, nEle, nEdge, nConn, nNodeEdge, nOldEdge, nUnitGraph, nStatsGraph;
+
+    /**
+     * Constructor.
+     *
+     * @param model the Model
+     */
+    SaveController(Model model) {
+        this.model = model;
+    }
+
+    /**
+     * Writes the current State of the Modelling into a JSON File which can be
+     * loaded.
+     *
+     * @param path the Path
+     * @throws IOException exception
+     */
+    void writeSave(String path) throws IOException, ArchiveException {
+
+        File dst = new File(path);
+        File holonFile = File.createTempFile("tmp", ".json");
+        holonFile.deleteOnExit();
+        dst.delete();
+
+        OutputStream output = new FileOutputStream(dst);
+        ArchiveOutputStream stream = new ArchiveStreamFactory().createArchiveOutputStream(ArchiveStreamFactory.ZIP,
+                output);
+
+        initNumeration();
+        JsonObject file = new JsonObject();
+        initialize(MODE.COMPLETE, file);
+        storeCategory(file);
+        storeCanvas(file);
+        storeStatistics(file);
+        storeData(stream);
+
+        FileWriter writer = new FileWriter(holonFile);
+        writer.write(model.getGson().toJson(file));
+        writer.flush();
+        writer.close();
+
+        addFileToSave(holonFile, stream, false);
+
+        stream.finish();
+        output.close();
+    }
+
+    /**
+     * Writes the windows status (its position and dimensions)
+     *
+     * @param path the Path where to save it
+     */
+    void writeWindowStatus(String path, int x, int y, int width, int height)
+            throws IOException, ArchiveException {
+        JsonObject file = new JsonObject();
+        initialize(MODE.SIZE, file);
+        storeWindowPosAndSize(file, x, y, width, height);
+
+        FileWriter writer = new FileWriter(path);
+        writer.write(model.getGson().toJson(file));
+        writer.flush();
+        writer.close();
+    }
+
+    /**
+     * Writes the Autosave File.
+     *
+     * @param path the Path
+     * @throws IOException Exception
+     */
+    void writeAutosave(String path) throws IOException {
+
+        initNumeration();
+        JsonObject file = new JsonObject();
+        initialize(MODE.PARTIAL, file);
+        storeCanvas(file);
+
+        FileWriter writer = new FileWriter(path);
+        writer.write(model.getGson().toJson(file));
+
+        writer.flush();
+        writer.close();
+    }
+
+    /**
+     * Writes the Category File in Case of Changes
+     */
+    void writeCategory(String path) throws IOException {
+
+        initNumeration();
+        JsonObject file = new JsonObject();
+        initialize(MODE.CATEGORY, file);
+        storeCategory(file);
+
+        FileWriter writer = new FileWriter(path);
+        writer.write(model.getGson().toJson(file));
+
+        writer.flush();
+        writer.close();
+
+    }
+
+    /**
+     * Write needed default parameter into the JsonObject. Can be extended later
+     * on
+     */
+    private void initialize(MODE mode, JsonObject file) {
+        switch (mode) {
+            case COMPLETE:
+                file.add("MODE", new JsonPrimitive(mode.name()));
+                file.add("IDCOUNTER", new JsonPrimitive(IdCounter.getCounter()));
+                file.add("IDCOUNTERELEMENT", new JsonPrimitive(IdCounterElem.getCounter()));
+                file.add("CANVAS_SIZE_X", new JsonPrimitive(model.getCanvasX()));
+                file.add("CANVAS_SIZE_Y", new JsonPrimitive(model.getCanvasY()));
+                break;
+            case PARTIAL:
+                file.add("MODE", new JsonPrimitive(mode.name()));
+                file.add("IDCOUNTER", new JsonPrimitive(IdCounter.getCounter()));
+                file.add("IDCOUNTERELEMENT", new JsonPrimitive(IdCounterElem.getCounter()));
+                file.add("CANVAS_SIZE_X", new JsonPrimitive(model.getCanvasX()));
+                file.add("CANVAS_SIZE_Y", new JsonPrimitive(model.getCanvasY()));
+                break;
+            case CATEGORY:
+                file.add("MODE", new JsonPrimitive(mode.name()));
+                break;
+            case SIZE:
+                file.add("MODE", new JsonPrimitive(mode.name()));
+            default:
+                break;
+        }
+
+    }
+
+    /**
+     * Store all Categories and Object into a Json File via Serialization
+     */
+    private void storeCategory(JsonObject file) {
+        // forall categories store them into the jsontree
+        for (Category cat : model.getCategories()) {
+            String key = "CATEGORY" + getNumerator(NUMTYPE.CATEGORY);
+
+            file.add(key, new JsonPrimitive(cat.getName()));
+            // forall object in the category store them into the jsontree
+            for (AbstractCpsObject obj : cat.getObjects()) {
+                file.add("CGOBJECT" + getNumerator(NUMTYPE.OBJECT),
+                        model.getGson().toJsonTree(obj, AbstractCpsObject.class));
+                // if its a holonobject add elements too
+                if (obj instanceof HolonObject)
+                    elementsToJson(TYPE.CATEGORY, file, obj);
+            }
+        }
+    }
+
+    private void storeWindowPosAndSize(JsonObject file, int x, int y, int width, int height) {
+        file.add("POS_X", new JsonPrimitive(x));
+        file.add("POS_Y", new JsonPrimitive(y));
+        file.add("WIDTH", new JsonPrimitive(width));
+        file.add("HEIGHT", new JsonPrimitive(height));
+
+    }
+
+    /**
+     * Travers through all Objects via BFS and Stores everything relevant
+     */
+    private void storeCanvas(JsonObject file) {
+        ArrayDeque<AbstractCpsObject> queue = new ArrayDeque<>();
+        AbstractCpsObject u = null;
+        // put all objects into queue since there is not starting object
+        for (AbstractCpsObject cps : model.getObjectsOnCanvas()) {
+            queue.add(cps);
+        }
+        // while quene not empty
+        while (!queue.isEmpty()) {
+
+            // u = current node
+            u = queue.pop();
+            // add currentnode into jsontree
+            String key = "CVSOBJECT" + getNumerator(NUMTYPE.OBJECT);
+            file.add(key, model.getGson().toJsonTree(u, AbstractCpsObject.class));
+            // and its connections too
+            edgeToJson(EDGETYPE.CONNECTION, file, u.getId(), u.getConnections());
+            // if holonobject elements too
+            if (u instanceof HolonObject)
+                elementsToJson(TYPE.CANVAS, file, u);
+            // if switch graphpoints too
+            if (u instanceof HolonSwitch)
+                if (((HolonSwitch) u).getGraphPoints().size() != 0)
+                    unitgraphToJson(GRAPHTYPE.SWITCH, file, u.getId(), ((HolonSwitch) u).getGraphPoints());
+            // if uppernode put all nodes inside the uppernode into queue
+            if (u instanceof CpsUpperNode) {
+                for (AbstractCpsObject adjacent : ((CpsUpperNode) u).getNodes()) {
+                    queue.add(adjacent);
+                }
+                // dont forget to add the nodeedges and oldedges
+                edgeToJson(EDGETYPE.NODE, file, u.getId(), ((CpsUpperNode) u).getNodeEdges());
+                edgeToJson(EDGETYPE.OLD, file, u.getId(), ((CpsUpperNode) u).getOldEdges());
+            }
+        }
+        // lastly add canvasedges into json
+        edgeToJson(EDGETYPE.CANVAS, file, 0, model.getEdgesOnCanvas());
+
+    }
+
+    private void storeStatistics(JsonObject file) {
+        trackedToJson(file);
+        statisticgraphToJson(file);
+    }
+
+    /**
+     * Save wanted Data
+     */
+    private void storeData(ArchiveOutputStream stream) throws IOException {
+        File images = new File(System.getProperty("user.home") + "/.config/HolonGUI/Images");
+        File background = new File(System.getProperty("user.home") + "/.config/HolonGUI/BackgroundImages");
+        addFilesToSave(images, stream);
+        addFilesToSave(background, stream);
+
+    }
+
+    /**
+     * Stores Category or Canvas Elements into Json
+     */
+    void elementsToJson(TYPE type, JsonObject file, AbstractCpsObject obj) {
+        JsonObject temp = new JsonObject();
+        String key = null;
+        // forall elements store them into json and include the id of the object
+        for (HolonElement ele : ((HolonObject) obj).getElements()) {
+            temp.add("properties", model.getGson().toJsonTree(ele));
+            temp.add("ID", new JsonPrimitive(obj.getId()));
+            // switch for deciding the key
+            switch (type) {
+                case CANVAS:
+                    key = "CVSELEMENT" + getNumerator(NUMTYPE.ELEMENT);
+                    break;
+                case CATEGORY:
+                    key = "CGELEMENT" + getNumerator(NUMTYPE.ELEMENT);
+                    break;
+                default:
+                    break;
+            }
+            file.add(key, model.getGson().toJsonTree(temp));
+            // if there are gps add them into
+            if (ele.getGraphPoints().size() != 0)
+                unitgraphToJson(GRAPHTYPE.ELEMENT, file, ele.getId(), ele.getGraphPoints());
+            temp = new JsonObject();
+        }
+
+    }
+
+    /**
+     * Put the UnitGraphs of Switches or Elements into Json
+     */
+    void unitgraphToJson(GRAPHTYPE type, JsonObject file, int id, LinkedList<Point> graph) {
+
+        JsonObject temp = new JsonObject();
+        String key = null;
+        // forall points add them
+        for (int i = 0; i < graph.size(); i++) {
+            temp.add("" + i, new JsonPrimitive(graph.get(i).x + ":" + graph.get(i).y));
+        }
+        // decide key
+        switch (type) {
+            case SWITCH:
+                key = "SWUNITGRAPH" + getNumerator(NUMTYPE.UNITGRAPH);
+                break;
+            case ELEMENT:
+                key = "ELEUNITGRAPH" + getNumerator(NUMTYPE.UNITGRAPH);
+                break;
+            default:
+                break;
+        }
+        // add id of element so it can be found again
+        temp.add("ID", new JsonPrimitive(id));
+
+        file.add(key, model.getGson().toJsonTree(temp));
+    }
+
+    /**
+     * Canvas-Edge, Connections, Node-Edge and Old-Edges to json
+     */
+    private void edgeToJson(EDGETYPE type, JsonObject file, int id, ArrayList<CpsEdge> arr) {
+        String k = null;
+        boolean b = false;
+        JsonObject temp = new JsonObject();
+
+        for (CpsEdge edge : arr) {
+            // 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 CANVAS:
+                    k = "CVSEDGE" + getNumerator(NUMTYPE.EDGE);
+                    break;
+                case CONNECTION:
+                    k = "CONNEDGE" + getNumerator(NUMTYPE.CONNECTION);
+                    break;
+                case NODE:
+                    temp.add("ID", new JsonPrimitive(id));
+                    k = "NODEEDGE" + getNumerator(NUMTYPE.NODEEDGE);
+                    break;
+                case OLD:
+                    temp.add("ID", new JsonPrimitive(id));
+                    k = "OLDEDGE" + 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();
+        }
+
+    }
+
+    private void trackedToJson(JsonObject file) {
+        JsonObject temp = new JsonObject();
+        String key = "TRACKED";
+        // forall points add them
+        for (int i = 0; i < model.getTrackingObj().size(); i++) {
+            temp.add("" + i, new JsonPrimitive(model.getTrackingObj().get(i).getId()));
+        }
+
+        file.add(key, model.getGson().toJsonTree(temp));
+    }
+
+    private void statisticgraphToJson(JsonObject file) {
+        JsonObject temp = new JsonObject();
+
+        List<String> keys = new ArrayList<>(model.getGraphTable().keySet());
+
+        for (String k : keys) {
+            JsonObject dataSet = new JsonObject();
+            for (int i = 0; i < model.getGraphTable().get(k).getStatGraph().getDataSets().size(); i++) {
+                TrackedDataSet set = model.getGraphTable().get(k).getStatGraph().getDataSets().get(i);
+                AbstractCpsObject cps = set.getCpsObject();
+
+                dataSet.add("ID", (cps == null ? null : new JsonPrimitive(cps.getId())));
+                dataSet.add("COLOR", model.getGson().toJsonTree(set.getColor(), Color.class));
+                dataSet.add("PROPERTY", new JsonPrimitive(set.getProperty()));
+                temp.add("" + i, model.getGson().toJsonTree(dataSet));
+                dataSet = new JsonObject();
+            }
+            temp.add("KEY", new JsonPrimitive(k));
+
+            file.add("STATSGRAPH" + getNumerator(NUMTYPE.STATSGRAPH), model.getGson().toJsonTree(temp));
+            temp = new JsonObject();
+        }
+
+    }
+
+    /**
+     * Differs Between Single file or whole Directory to Store
+     */
+    private void addFilesToSave(File src, ArchiveOutputStream stream) throws IOException {
+        if (!src.exists())
+            return;
+
+        ArrayList<File> files = new ArrayList<>();
+        files.addAll(Arrays.asList(src.listFiles()));
+
+        for (File file : files) {
+            if (file.isDirectory())
+                addFilesToSave(file, stream);
+            else
+                addFileToSave(file, stream, true);
+        }
+
+    }
+
+    /**
+     * Add a File into the Archive
+     */
+    private void addFileToSave(File src, ArchiveOutputStream stream, boolean dir) throws IOException {
+        String entryName = (dir ? src.getCanonicalPath() : src.getName());
+
+        entryName = checkOS(entryName);
+
+        ZipArchiveEntry entry = new ZipArchiveEntry(entryName);
+        stream.putArchiveEntry(entry);
+        BufferedInputStream input = new BufferedInputStream(new FileInputStream(src));
+
+        IOUtils.copy(input, stream);
+        input.close();
+        stream.closeArchiveEntry();
+    }
+
+    private String checkOS(String entryName) {
+        String os = System.getProperty("os.name").toLowerCase();
+        String ret = entryName;
+        String partition = null;
+
+        if (os.contains("windows")) {
+            partition = ret.substring(0, ret.indexOf(":") + 1);
+            ret = ret.replace(System.getProperty("user.home") + "\\.config\\HolonGUI\\", "");
+            ret = ret.replace(partition, "");
+        }
+        if (os.contains("mac")) {
+            // dosmth
+            ret = ret.replace(System.getProperty("user.home") + "/.config/HolonGUI/", "");
+        }
+        if (os.contains("linux")) {
+            // dosmth
+            ret = ret.replace(System.getProperty("user.home") + "/.config/HolonGUI/", "");
+        }
+        if (os.contains("solaris")) {
+            // dosmth
+        }
+        return ret;
+    }
+
+    /**
+     * Just initialize the Numerators for the Json Keys. Maybe bad Style..
+     */
+    void initNumeration() {
+        this.nCat = this.nObj = this.nEle = this.nEdge = this.nConn = this.nNodeEdge = this.nOldEdge = this.nStatsGraph = 0;
+    }
+
+    /**
+     * Get the wanted numerator and increment it
+     */
+    int getNumerator(NUMTYPE type) {
+
+        switch (type) {
+            case CATEGORY:
+                return nCat++;
+            case OBJECT:
+                return nObj++;
+            case ELEMENT:
+                return nEle++;
+            case EDGE:
+                return nEdge++;
+            case CONNECTION:
+                return nConn++;
+            case NODEEDGE:
+                return nNodeEdge++;
+            case OLDEDGE:
+                return nOldEdge++;
+            case UNITGRAPH:
+                return nUnitGraph++;
+            case STATSGRAPH:
+                return nStatsGraph++;
+
+            default:
+                break;
+        }
+        return -1;
+    }
+
+    public enum MODE {
+        COMPLETE, PARTIAL, CATEGORY, SIZE,
+    }
+
+    public enum TYPE {
+        CATEGORY, CANVAS
+    }
+
+    public enum EDGETYPE {
+        CANVAS, CONNECTION, NODE, OLD, LAYER
+    }
+
+    public enum NUMTYPE {
+        CATEGORY, OBJECT, ELEMENT, EDGE, CONNECTION, NODEEDGE, OLDEDGE, UNITGRAPH, STATSGRAPH
+    }
+
+    public enum GRAPHTYPE {
+        SWITCH, ELEMENT
+    }
 
 }

+ 46 - 6
src/ui/view/GUI.java

@@ -269,17 +269,38 @@ public class GUI implements CategoryListener {
     private void initialize() {
         frmCyberPhysical = new JFrame();
         frmCyberPhysical.setTitle("Cyber Physical Systems Model");
-        frmCyberPhysical.setBounds(100, 100, 1000, 800);
+        // try to restore old position/dimensions
+        ArrayList<Integer> savedWindowDim = controller.loadSavedWindowDimensionsIfExistent();
+        if (savedWindowDim.size() == 4) {
+            frmCyberPhysical.setBounds(savedWindowDim.get(0), savedWindowDim.get(1),
+                    savedWindowDim.get(2), savedWindowDim.get(3));
+        }
+
+        // if the upper part of the window is showing, the windows can still be moved,
+        // but if it is not, we need to move it to somewhere else
+        if (savedWindowDim.size() != 4 || !isUpperPanelInsideBounds()) {
+            frmCyberPhysical.setBounds(100, 100, 1000, 800);
+            frmCyberPhysical.setExtendedState(JFrame.MAXIMIZED_BOTH);
+        }
         frmCyberPhysical.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
-        frmCyberPhysical.setExtendedState(JFrame.MAXIMIZED_BOTH);
+
         frmCyberPhysical.addWindowListener(new java.awt.event.WindowAdapter() {
             @Override
             public void windowClosing(java.awt.event.WindowEvent windowEvent) {
                 if (JOptionPane.showConfirmDialog(frmCyberPhysical, Languages.getLanguage()[88],
                         "Cyber Physical Systems Model", JOptionPane.YES_NO_OPTION,
                         JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION) {
-                    controller
-                            .deleteDirectory(new File(System.getProperty("user.home") + "/.config/HolonGUI/Autosave"));
+                    controller.deleteDirectory(new File(System.getProperty("user.home")
+                            + "/.config/HolonGUI/Autosave"));
+
+                    // try to save the position and size of the window, such that (if possible)
+                    // it can be opened in the same position the next time
+                    try {
+                        controller.savePosAndSizeOfWindow(frmCyberPhysical.getX(), frmCyberPhysical.getY(),
+                                frmCyberPhysical.getWidth(), frmCyberPhysical.getHeight());
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
                     System.exit(0);
                 }
             }
@@ -1754,8 +1775,6 @@ public class GUI implements CategoryListener {
         splitPaneCanvasConsole.setLeftComponent(tabbedPaneOriginal);
         tabbedPaneOriginal.addTab("View", tabbedPaneInnerOriginal);
         tabbedPaneInnerOriginal.addTab("Main Grid", canvasSP);
-//        tabbedPaneSplit.addTab("View", tabbedPaneInnerSplit);
-//        tabbedPaneInnerSplit.addTab("Main Grid", null);
         tabbedPaneOriginal.addTab("Statistics", statScrollPane);
         tabbedPaneOriginal.addTab("Holon", holonCanvas);
         FlexiblePane flexPane = new FlexiblePane(controller);
@@ -1855,6 +1874,27 @@ public class GUI implements CategoryListener {
         splitGraphHolonEl.setDividerLocation(0);
     }
 
+    private boolean isUpperPanelInsideBounds() {
+        int x = frmCyberPhysical.getX();
+        int y = frmCyberPhysical.getY();
+        int width = frmCyberPhysical.getWidth();
+
+        // get all connected screen devices
+        GraphicsDevice[] screenDevices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
+        boolean isUpperPanelVisible = false;
+
+        // and check whether they contain the upper left or upper right point of the frame
+        for (GraphicsDevice device : screenDevices) {
+            Rectangle bounds = device.getDefaultConfiguration().getBounds();
+            if (bounds.contains(x, y) || bounds.contains(x + width, y)) {
+                isUpperPanelVisible = true;
+                break;
+            }
+        }
+
+        return isUpperPanelVisible;
+    }
+
     /**
      * Sets up autosave if no old one is loaded at the beginning
      *