fdShell.dispose();
if (result != null)
{
- new Editor((DeserializedSubmodelComponent) SubmodelComponentSerializer.deserialize(new ViewModelModifiable(), result));
+ new Editor((DeserializedSubmodelComponent) IndirectGUIComponentCreator.createComponent(new ViewModelModifiable(),
+ "file:" + result));
}
}
}
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
+import com.google.gson.JsonObject;
import net.mograsim.logic.model.model.ViewModelModifiable;
import net.mograsim.logic.model.model.components.GUIComponent;
throw new IllegalArgumentException("Can't give params to a component deserialized from a JSON file");
try
{
- return SubmodelComponentSerializer.deserialize(model, resolvedID.substring(5), name, id, null);
+ String filename = resolvedID.substring(5);
+ JsonObject jsonContents = JsonHandler.readJson(filename, JsonObject.class);
+ SerializablePojo jsonContentsAsSerializablePojo = JsonHandler.parser.fromJson(jsonContents, SerializablePojo.class);
+ if (jsonContentsAsSerializablePojo.version == null)
+ return LegacySubmodelComponentSerializer.deserialize(model,
+ JsonHandler.parser.fromJson(jsonContents, LegacySubmodelComponentParams.class), name, id, null);
+ return SubmodelComponentSerializer.deserialize(model,
+ JsonHandler.parser.fromJson(jsonContents, SubmodelComponentParams.class), name, id, null);
}
catch (IOException e)
{
--- /dev/null
+package net.mograsim.logic.model.serializing;
+
+import java.io.IOException;
+
+import com.google.gson.JsonElement;
+
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.util.JsonHandler;
+
+/**
+ * This class contains all the information necessary to create a new {@link SubmodelComponent}
+ */
+public class LegacySubmodelComponentParams
+{
+ // basic stuff
+ public double width, height;
+ public LegacyInterfacePinParams[] interfacePins;
+ public LegacySubmodelParameters submodel;
+
+ // functionality that needs to be expressed in Java code
+ public String symbolRendererSnippetID;
+ public JsonElement symbolRendererParams;
+
+ public String outlineRendererSnippetID;
+ public JsonElement outlineRendererParams;
+
+ public String highLevelStateHandlerSnippetID;
+ public JsonElement highLevelStateHandlerParams;
+
+ public static class LegacyInterfacePinParams
+ {
+ public Point location;
+ public String name;
+ public int logicWidth;
+ }
+
+ public static class LegacySubmodelParameters
+ {
+ public double innerScale;
+ public LegacyInnerComponentParams[] subComps;
+ public LegacyInnerWireParams[] innerWires;
+
+ public static class LegacyInnerComponentParams
+ {
+ public String id;
+ public String name;
+ public Point pos;
+ public JsonElement params;
+ }
+
+ public static class LegacyInnerWireParams
+ {
+ public LegacyInnerPinParams pin1, pin2;
+ public String name;
+ public Point[] path;
+
+ public static class LegacyInnerPinParams
+ {
+ public String compName;
+ public String pinName;
+ }
+ }
+ }
+
+ public static LegacySubmodelComponentParams readJson(String path) throws IOException
+ {
+ return JsonHandler.readJson(path, LegacySubmodelComponentParams.class);
+ }
+
+ /**
+ * Writes this {@link LegacySubmodelComponentParams} object into a file in json format. The correct file extension is important! Check
+ * {@link LegacySubmodelComponentParams}.fileExtension
+ */
+ public void writeJson(String path)
+ {
+ try
+ {
+ JsonHandler.writeJson(this, path);
+ }
+ catch (IOException e)
+ {
+ System.err.println("Failed to write SubComponentParams to file");
+ e.printStackTrace();
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.mograsim.logic.model.serializing;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+
+import com.google.gson.JsonElement;
+
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.mograsim.logic.model.model.ViewModelModifiable;
+import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.model.wires.GUIWire;
+import net.mograsim.logic.model.model.wires.MovablePin;
+import net.mograsim.logic.model.model.wires.Pin;
+import net.mograsim.logic.model.serializing.LegacySubmodelComponentParams.LegacyInterfacePinParams;
+import net.mograsim.logic.model.serializing.LegacySubmodelComponentParams.LegacySubmodelParameters;
+import net.mograsim.logic.model.serializing.LegacySubmodelComponentParams.LegacySubmodelParameters.LegacyInnerComponentParams;
+import net.mograsim.logic.model.serializing.LegacySubmodelComponentParams.LegacySubmodelParameters.LegacyInnerWireParams;
+import net.mograsim.logic.model.serializing.LegacySubmodelComponentParams.LegacySubmodelParameters.LegacyInnerWireParams.LegacyInnerPinParams;
+import net.mograsim.logic.model.snippets.HighLevelStateHandler;
+import net.mograsim.logic.model.snippets.Renderer;
+import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
+import net.mograsim.logic.model.util.JsonHandler;
+
+/**
+ * Creates {@link SubmodelComponent}s from {@link LegacySubmodelComponentParams}
+ *
+ * @author Fabian Stemmler
+ * @author Daniel Kirschten
+ */
+public final class LegacySubmodelComponentSerializer
+{
+ // convenience methods
+
+ /**
+ * Like {@link #deserialize(ViewModelModifiable, LegacySubmodelComponentParams)}, but first reading the
+ * {@link LegacySubmodelComponentParams} from the given file path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath) throws IOException
+ {
+ return deserialize(model, JsonHandler.readJson(sourcePath, LegacySubmodelComponentParams.class));
+ }
+
+ /**
+ * Like {@link #deserialize(ViewModelModifiable, LegacySubmodelComponentParams, String, JsonElement)}, but first reading the
+ * {@link LegacySubmodelComponentParams} from the given file path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath, String idForSerializingOverride,
+ JsonElement paramsForSerializingOverride) throws IOException
+ {
+ return deserialize(model, JsonHandler.readJson(sourcePath, LegacySubmodelComponentParams.class), idForSerializingOverride,
+ paramsForSerializingOverride);
+ }
+
+ /**
+ * Like {@link #deserialize(ViewModelModifiable, LegacySubmodelComponentParams, String)}, but first reading the
+ * {@link LegacySubmodelComponentParams} from the given file path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath, String name) throws IOException
+ {
+ return deserialize(model, JsonHandler.readJson(sourcePath, LegacySubmodelComponentParams.class), name);
+ }
+
+ /**
+ * Like {@link #deserialize(ViewModelModifiable, LegacySubmodelComponentParams, String, String, JsonElement)}, but first reading the
+ * {@link LegacySubmodelComponentParams} from the given file path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath, String name, String idForSerializingOverride,
+ JsonElement paramsForSerializingOverride) throws IOException
+ {
+ return deserialize(model, JsonHandler.readJson(sourcePath, LegacySubmodelComponentParams.class), name, idForSerializingOverride,
+ paramsForSerializingOverride);
+ }
+
+ /**
+ * {@link #deserialize(ViewModelModifiable, LegacySubmodelComponentParams, String, String, JsonElement)} with no
+ * <code>idForSerializingOverride</code> set and using the default name.
+ *
+ * @author Daniel Kirschten
+ */
+ public static SubmodelComponent deserialize(ViewModelModifiable model, LegacySubmodelComponentParams params)
+ {
+ return deserialize(model, params, null, null, null);
+ }
+
+ /**
+ * {@link #deserialize(ViewModelModifiable, LegacySubmodelComponentParams, String, String, JsonElement)} using the default name.
+ *
+ * @author Daniel Kirschten
+ */
+ public static SubmodelComponent deserialize(ViewModelModifiable model, LegacySubmodelComponentParams params,
+ String idForSerializingOverride, JsonElement paramsForSerializingOverride)
+ {
+ return deserialize(model, params, null, idForSerializingOverride, paramsForSerializingOverride);
+ }
+
+ /**
+ * {@link #deserialize(ViewModelModifiable, LegacySubmodelComponentParams, String, String, JsonElement)} with no
+ * <code>idForSerializingOverride</code> set.
+ *
+ * @author Daniel Kirschten
+ */
+ public static SubmodelComponent deserialize(ViewModelModifiable model, LegacySubmodelComponentParams params, String name)
+ {
+ return deserialize(model, params, name, null, null);
+ }
+
+ /**
+ * Like {@link #serialize(SubmodelComponent)}, but instead of returning the generated {@link LegacySubmodelComponentParams} they are
+ * written to a file at the given path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static void serialize(SubmodelComponent comp, String targetPath) throws IOException
+ {
+ JsonHandler.writeJson(serialize(comp), targetPath);
+ }
+
+ /**
+ * Like {@link #serialize(SubmodelComponent, Function)}, but instead of returning the generated {@link LegacySubmodelComponentParams}
+ * they are written to a file at the given path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static void serialize(SubmodelComponent comp, IdentifierGetter idGetter, String targetPath) throws IOException
+ {
+ JsonHandler.writeJson(serialize(comp, idGetter), targetPath);
+ }
+
+ /**
+ * {@link #serialize(SubmodelComponent, Function)} using a default {@link IdentifierGetter} (see <code>IdentifierGetter</code>'s
+ * {@link IdentifierGetter#IdentifierGetter() default constructor})
+ *
+ * @author Daniel Kirschten
+ */
+ public static LegacySubmodelComponentParams serialize(SubmodelComponent comp)
+ {
+ return serialize(comp, new IdentifierGetter());
+ }
+
+ // "core" methods
+ /**
+ * Creates a {@link SubmodelComponent} from the specified {@link LegacySubmodelComponentParams} with the given name.
+ * <p>
+ * When serializing a <code>SubmodelComponent</code>, it is undesired for every subcomponent to be serialized with its complete inner
+ * structure. Instead, these sub-<code>SubmodelComponent</code>s should be serialized with the ID and params which were used to
+ * determine the <code>SubmodelComponentParams</code> defining the sub-<code>SubmodelComponent</code>. Because of this, it is possible
+ * to override the ID and params used in {@link #serialize(SubmodelComponent, Function) serialize(...)} to describe this subcomponent.
+ * See there for details.
+ *
+ * @author Fabian Stemmler
+ * @author Daniel Kirschten
+ */
+ @SuppressWarnings("unused") // for GUIWire being created
+ public static SubmodelComponent deserialize(ViewModelModifiable model, LegacySubmodelComponentParams params, String name,
+ String idForSerializingOverride, JsonElement paramsForSerializingOverride)
+ {
+ DeserializedSubmodelComponent comp = new DeserializedSubmodelComponent(model, name, idForSerializingOverride,
+ paramsForSerializingOverride);
+ comp.setSubmodelScale(params.submodel.innerScale);
+ comp.setSize(params.width, params.height);
+ for (LegacyInterfacePinParams iPinParams : params.interfacePins)
+ comp.addSubmodelInterface(
+ new MovablePin(comp, iPinParams.name, iPinParams.logicWidth, iPinParams.location.x, iPinParams.location.y));
+ LegacySubmodelParameters submodelParams = params.submodel;
+ ViewModelModifiable submodelModifiable = comp.getSubmodelModifiable();
+ Map<String, GUIComponent> componentsByName = submodelModifiable.getComponentsByName();
+ GUIComponent[] components = new GUIComponent[submodelParams.subComps.length];
+ for (int i = 0; i < components.length; i++)
+ {
+ LegacyInnerComponentParams cParams = submodelParams.subComps[i];
+ components[i] = IndirectGUIComponentCreator.createComponent(submodelModifiable, cParams.id, cParams.params, cParams.name);
+ components[i].moveTo(cParams.pos.x, cParams.pos.y);
+ }
+
+ for (int i = 0; i < submodelParams.innerWires.length; i++)
+ {
+ LegacyInnerWireParams innerWire = submodelParams.innerWires[i];
+ new GUIWire(submodelModifiable, innerWire.name, componentsByName.get(innerWire.pin1.compName).getPin(innerWire.pin1.pinName),
+ componentsByName.get(innerWire.pin2.compName).getPin(innerWire.pin2.pinName), innerWire.path);
+ }
+ comp.setSymbolRenderer(SubmodelComponentSnippetSuppliers.symbolRendererSupplier.getSnippetSupplier(params.symbolRendererSnippetID)
+ .create(comp, params.symbolRendererParams));
+ comp.setOutlineRenderer(SubmodelComponentSnippetSuppliers.outlineRendererSupplier
+ .getSnippetSupplier(params.outlineRendererSnippetID).create(comp, params.outlineRendererParams));
+ comp.setHighLevelStateHandler(SubmodelComponentSnippetSuppliers.highLevelStateHandlerSupplier
+ .getSnippetSupplier(params.highLevelStateHandlerSnippetID).create(comp, params.highLevelStateHandlerParams));
+ return comp;
+ }
+
+ /**
+ * Returns {@link LegacySubmodelComponentParams}, which describe this {@link SubmodelComponent}. <br>
+ * Subcomponents are serialized in the following way: <br>
+ * If a subcomponent is a <code>SubmodelComponent</code> which has been deserialized, and it has an
+ * {@link DeserializedSubmodelComponent#idForSerializingOverride idForSerializingOverride} set (e.g. non-null; see
+ * {@link #deserialize(ViewModelModifiable, LegacySubmodelComponentParams, String, String, JsonElement) deserialize(...)}), this ID and
+ * the component's {@link DeserializedSubmodelComponent#paramsForSerializingOverride paramsForSerializingOverride} are written.<br>
+ * If this case doesn't apply (e.g. if the subcomponent is not a <code>SubmodelComponent</code>; or it is a
+ * <code>SubmodelComponent</code>, but hasn't been deserialized; or it has no
+ * {@link DeserializedSubmodelComponent#idForSerializingOverride idForSerializingOverride} set), the ID defined by <code>idGetter</code>
+ * and the params obtained by {@link GUIComponent#getParamsForSerializing() getParams()} are written.<br>
+ * CodeSnippets are serialized using the ID defined by <code>idGetter</code> and the params obtained by the respective
+ * <coce>getParamsForSerializing</code> methods ({@link Renderer#getParamsForSerializing()}).
+ *
+ * @author Fabian Stemmler
+ * @author Daniel Kirschten
+ */
+ public static LegacySubmodelComponentParams serialize(SubmodelComponent comp, IdentifierGetter idGetter)
+ {
+ LegacySubmodelParameters submodelParams = new LegacySubmodelParameters();
+ submodelParams.innerScale = comp.getSubmodelScale();
+
+ Map<String, GUIComponent> components = new HashMap<>(comp.submodel.getComponentsByName());
+ components.remove(SubmodelComponent.SUBMODEL_INTERFACE_NAME);
+ LegacyInnerComponentParams[] componentParams = new LegacyInnerComponentParams[components.size()];
+ int i1 = 0;
+ for (GUIComponent innerComponent : components.values())
+ {
+ LegacyInnerComponentParams innerComponentParams = new LegacyInnerComponentParams();
+ componentParams[i1] = innerComponentParams;
+ innerComponentParams.pos = new Point(innerComponent.getPosX(), innerComponent.getPosY());
+ DeserializedSubmodelComponent innerCompCasted;
+ if (innerComponent instanceof DeserializedSubmodelComponent
+ && (innerCompCasted = (DeserializedSubmodelComponent) innerComponent).idForSerializingOverride != null)
+ {
+ innerComponentParams.id = innerCompCasted.idForSerializingOverride;
+ innerComponentParams.params = innerCompCasted.paramsForSerializingOverride;
+ } else
+ {
+ innerComponentParams.id = idGetter.componentIDs.apply(innerComponent);
+ innerComponentParams.params = innerComponent.getParamsForSerializing(idGetter);
+ }
+ innerComponentParams.name = innerComponent.name;
+ i1++;
+ }
+ submodelParams.subComps = componentParams;
+
+ Collection<GUIWire> wires = comp.submodel.getWiresByName().values();
+ LegacyInnerWireParams wireParams[] = new LegacyInnerWireParams[wires.size()];
+ i1 = 0;
+ for (GUIWire innerWire : wires)
+ {
+ LegacyInnerWireParams innerWireParams = new LegacyInnerWireParams();
+ wireParams[i1] = innerWireParams;
+ LegacyInnerPinParams pin1Params = new LegacyInnerPinParams(), pin2Params = new LegacyInnerPinParams();
+
+ pin1Params.pinName = innerWire.getPin1().name;
+ pin1Params.compName = innerWire.getPin1().component.name;
+ pin2Params.pinName = innerWire.getPin2().name;
+ pin2Params.compName = innerWire.getPin2().component.name;
+ innerWireParams.name = innerWire.name;
+ innerWireParams.pin1 = pin1Params;
+ innerWireParams.pin2 = pin2Params;
+ innerWireParams.path = innerWire.getPath();
+ i1++;
+ }
+ submodelParams.innerWires = wireParams;
+
+ LegacySubmodelComponentParams params = new LegacySubmodelComponentParams();
+ params.submodel = submodelParams;
+
+ params.width = comp.getWidth();
+ params.height = comp.getHeight();
+
+ LegacyInterfacePinParams[] iPins = new LegacyInterfacePinParams[comp.getPins().size()];
+ int i = 0;
+ for (Pin p : comp.getPins().values())
+ {
+ LegacyInterfacePinParams iPinParams = new LegacyInterfacePinParams();
+ iPins[i] = iPinParams;
+ iPinParams.location = p.getRelPos();
+ iPinParams.name = p.name;
+ iPinParams.logicWidth = p.logicWidth;
+ i++;
+ }
+ params.interfacePins = iPins;
+
+ Renderer symbolRenderer = comp.getSymbolRenderer();
+ if (symbolRenderer != null)
+ {
+ params.symbolRendererSnippetID = idGetter.symbolRendererIDs.apply(symbolRenderer);
+ params.symbolRendererParams = symbolRenderer.getParamsForSerializingJSON(idGetter);
+ }
+
+ Renderer outlineRenderer = comp.getOutlineRenderer();
+ if (outlineRenderer != null)
+ {
+ params.outlineRendererSnippetID = idGetter.outlineRendererIDs.apply(outlineRenderer);
+ params.outlineRendererParams = outlineRenderer.getParamsForSerializingJSON(idGetter);
+ }
+
+ HighLevelStateHandler highLevelStateHandler = comp.getHighLevelStateHandler();
+ if (highLevelStateHandler != null)
+ {
+ params.highLevelStateHandlerSnippetID = idGetter.highLevelStateHandlerIDs.apply(highLevelStateHandler);
+ params.highLevelStateHandlerParams = highLevelStateHandler.getParamsForSerializingJSON(idGetter);
+ }
+
+ return params;
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.mograsim.logic.model.serializing;
+
+import net.mograsim.logic.model.util.Version;
+
+/**
+ * This class is the superclass of all POJOs that can be serialized to JSON.
+ *
+ * @author Daniel Kirschten
+ *
+ */
+public class SerializablePojo
+{
+ public Version version;
+
+ public SerializablePojo(Version version)
+ {
+ this.version = version;
+ }
+}
\ No newline at end of file
package net.mograsim.logic.model.serializing;
-import java.io.IOException;
-
import com.google.gson.JsonElement;
import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-import net.mograsim.logic.model.util.JsonHandler;
+import net.mograsim.logic.model.util.Version;
/**
* This class contains all the information necessary to create a new {@link SubmodelComponent}
*/
-public class SubmodelComponentParams
+public class SubmodelComponentParams extends SerializablePojo
{
// basic stuff
public double width, height;
public InterfacePinParams[] interfacePins;
- public SubmodelParameters submodel;
+ public double innerScale;
+ public ViewModelParams submodel;
// functionality that needs to be expressed in Java code
public String symbolRendererSnippetID;
public String highLevelStateHandlerSnippetID;
public JsonElement highLevelStateHandlerParams;
+ public SubmodelComponentParams(Version version)
+ {
+ super(version);
+ }
+
public static class InterfacePinParams
{
public Point location;
public String name;
public int logicWidth;
}
-
- public static class SubmodelParameters
- {
- public double innerScale;
- public InnerComponentParams[] subComps;
- public InnerWireParams[] innerWires;
-
- public static class InnerComponentParams
- {
- public String id;
- public String name;
- public Point pos;
- public JsonElement params;
- }
-
- public static class InnerWireParams
- {
- public InnerPinParams pin1, pin2;
- public String name;
- public Point[] path;
-
- public static class InnerPinParams
- {
- public String compName;
- public String pinName;
- }
- }
- }
-
- public static SubmodelComponentParams readJson(String path) throws IOException
- {
- return JsonHandler.readJson(path, SubmodelComponentParams.class);
- }
-
- /**
- * Writes this {@link SubmodelComponentParams} object into a file in json format. The correct file extension is important! Check
- * {@link SubmodelComponentParams}.fileExtension
- */
- public void writeJson(String path)
- {
- try
- {
- JsonHandler.writeJson(this, path);
- }
- catch (IOException e)
- {
- System.err.println("Failed to write SubComponentParams to file");
- e.printStackTrace();
- }
- }
}
\ No newline at end of file
package net.mograsim.logic.model.serializing;
import java.io.IOException;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Function;
import com.google.gson.JsonElement;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
import net.mograsim.logic.model.model.ViewModelModifiable;
-import net.mograsim.logic.model.model.components.GUIComponent;
import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-import net.mograsim.logic.model.model.wires.GUIWire;
import net.mograsim.logic.model.model.wires.MovablePin;
import net.mograsim.logic.model.model.wires.Pin;
import net.mograsim.logic.model.serializing.SubmodelComponentParams.InterfacePinParams;
-import net.mograsim.logic.model.serializing.SubmodelComponentParams.SubmodelParameters;
-import net.mograsim.logic.model.serializing.SubmodelComponentParams.SubmodelParameters.InnerComponentParams;
-import net.mograsim.logic.model.serializing.SubmodelComponentParams.SubmodelParameters.InnerWireParams;
-import net.mograsim.logic.model.serializing.SubmodelComponentParams.SubmodelParameters.InnerWireParams.InnerPinParams;
import net.mograsim.logic.model.snippets.HighLevelStateHandler;
import net.mograsim.logic.model.snippets.Renderer;
import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
import net.mograsim.logic.model.util.JsonHandler;
+import net.mograsim.logic.model.util.Version;
/**
* Creates {@link SubmodelComponent}s from {@link SubmodelComponentParams}
*/
public final class SubmodelComponentSerializer
{
+ public static final Version CURRENT_JSON_VERSION = Version.parseSemver("0.1.4");
// convenience methods
/**
}
/**
- * Like {@link #serialize(SubmodelComponent, Function)}, but instead of returning the generated {@link SubmodelComponentParams} they are
- * written to a file at the given path.
+ * Like {@link #serialize(SubmodelComponent, IdentifierGetter)}, but instead of returning the generated {@link SubmodelComponentParams}
+ * they are written to a file at the given path.
*
* @author Daniel Kirschten
*/
}
/**
- * {@link #serialize(SubmodelComponent, Function)} using a default {@link IdentifierGetter} (see <code>IdentifierGetter</code>'s
+ * {@link #serialize(SubmodelComponent, IdentifierGetter)} using a default {@link IdentifierGetter} (see <code>IdentifierGetter</code>'s
* {@link IdentifierGetter#IdentifierGetter() default constructor})
*
* @author Daniel Kirschten
* When serializing a <code>SubmodelComponent</code>, it is undesired for every subcomponent to be serialized with its complete inner
* structure. Instead, these sub-<code>SubmodelComponent</code>s should be serialized with the ID and params which were used to
* determine the <code>SubmodelComponentParams</code> defining the sub-<code>SubmodelComponent</code>. Because of this, it is possible
- * to override the ID and params used in {@link #serialize(SubmodelComponent, Function) serialize(...)} to describe this subcomponent.
- * See there for details.
+ * to override the ID and params used in {@link #serialize(SubmodelComponent, IdentifierGetter) serialize(...)} to describe this
+ * subcomponent. See there for details.
*
* @author Fabian Stemmler
* @author Daniel Kirschten
{
DeserializedSubmodelComponent comp = new DeserializedSubmodelComponent(model, name, idForSerializingOverride,
paramsForSerializingOverride);
- comp.setSubmodelScale(params.submodel.innerScale);
+ comp.setSubmodelScale(params.innerScale);
comp.setSize(params.width, params.height);
for (InterfacePinParams iPinParams : params.interfacePins)
comp.addSubmodelInterface(
new MovablePin(comp, iPinParams.name, iPinParams.logicWidth, iPinParams.location.x, iPinParams.location.y));
- SubmodelParameters submodelParams = params.submodel;
ViewModelModifiable submodelModifiable = comp.getSubmodelModifiable();
- Map<String, GUIComponent> componentsByName = submodelModifiable.getComponentsByName();
- GUIComponent[] components = new GUIComponent[submodelParams.subComps.length];
- for (int i = 0; i < components.length; i++)
- {
- InnerComponentParams cParams = submodelParams.subComps[i];
- components[i] = IndirectGUIComponentCreator.createComponent(submodelModifiable, cParams.id, cParams.params, cParams.name);
- components[i].moveTo(cParams.pos.x, cParams.pos.y);
- }
-
- for (int i = 0; i < submodelParams.innerWires.length; i++)
- {
- InnerWireParams innerWire = submodelParams.innerWires[i];
- new GUIWire(submodelModifiable, innerWire.name, componentsByName.get(innerWire.pin1.compName).getPin(innerWire.pin1.pinName),
- componentsByName.get(innerWire.pin2.compName).getPin(innerWire.pin2.pinName), innerWire.path);
- }
+ ViewModelSerializer.deserialize(comp.getSubmodelModifiable(), params.submodel);
comp.setSymbolRenderer(SubmodelComponentSnippetSuppliers.symbolRendererSupplier.getSnippetSupplier(params.symbolRendererSnippetID)
.create(comp, params.symbolRendererParams));
comp.setOutlineRenderer(SubmodelComponentSnippetSuppliers.outlineRendererSupplier
/**
* Returns {@link SubmodelComponentParams}, which describe this {@link SubmodelComponent}. <br>
- * Subcomponents are serialized in the following way: <br>
- * If a subcomponent is a <code>SubmodelComponent</code> which has been deserialized, and it has an
- * {@link DeserializedSubmodelComponent#idForSerializingOverride idForSerializingOverride} set (e.g. non-null; see
- * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement) deserialize(...)}), this ID and the
- * component's {@link DeserializedSubmodelComponent#paramsForSerializingOverride paramsForSerializingOverride} are written.<br>
- * If this case doesn't apply (e.g. if the subcomponent is not a <code>SubmodelComponent</code>; or it is a
- * <code>SubmodelComponent</code>, but hasn't been deserialized; or it has no
- * {@link DeserializedSubmodelComponent#idForSerializingOverride idForSerializingOverride} set), the ID defined by <code>idGetter</code>
- * and the params obtained by {@link GUIComponent#getParamsForSerializing() getParams()} are written.<br>
+ * See {@link ViewModelSerializer#serialize(net.mograsim.logic.model.model.ViewModel, IdentifierGetter)
+ * ViewModelSerializer.serialize(...)} for how subcomponents are serialized.<br>
* CodeSnippets are serialized using the ID defined by <code>idGetter</code> and the params obtained by the respective
* <coce>getParamsForSerializing</code> methods ({@link Renderer#getParamsForSerializing()}).
*
*/
public static SubmodelComponentParams serialize(SubmodelComponent comp, IdentifierGetter idGetter)
{
- SubmodelParameters submodelParams = new SubmodelParameters();
- submodelParams.innerScale = comp.getSubmodelScale();
-
- Map<String, GUIComponent> components = new HashMap<>(comp.submodel.getComponentsByName());
- components.remove(SubmodelComponent.SUBMODEL_INTERFACE_NAME);
- InnerComponentParams[] componentParams = new InnerComponentParams[components.size()];
- int i1 = 0;
- for (GUIComponent innerComponent : components.values())
- {
- InnerComponentParams innerComponentParams = new InnerComponentParams();
- componentParams[i1] = innerComponentParams;
- innerComponentParams.pos = new Point(innerComponent.getPosX(), innerComponent.getPosY());
- DeserializedSubmodelComponent innerCompCasted;
- if (innerComponent instanceof DeserializedSubmodelComponent
- && (innerCompCasted = (DeserializedSubmodelComponent) innerComponent).idForSerializingOverride != null)
- {
- innerComponentParams.id = innerCompCasted.idForSerializingOverride;
- innerComponentParams.params = innerCompCasted.paramsForSerializingOverride;
- } else
- {
- innerComponentParams.id = idGetter.componentIDs.apply(innerComponent);
- innerComponentParams.params = innerComponent.getParamsForSerializing(idGetter);
- }
- innerComponentParams.name = innerComponent.name;
- i1++;
- }
- submodelParams.subComps = componentParams;
-
- Collection<GUIWire> wires = comp.submodel.getWiresByName().values();
- InnerWireParams wireParams[] = new InnerWireParams[wires.size()];
- i1 = 0;
- for (GUIWire innerWire : wires)
- {
- InnerWireParams innerWireParams = new InnerWireParams();
- wireParams[i1] = innerWireParams;
- InnerPinParams pin1Params = new InnerPinParams(), pin2Params = new InnerPinParams();
-
- pin1Params.pinName = innerWire.getPin1().name;
- pin1Params.compName = innerWire.getPin1().component.name;
- pin2Params.pinName = innerWire.getPin2().name;
- pin2Params.compName = innerWire.getPin2().component.name;
- innerWireParams.name = innerWire.name;
- innerWireParams.pin1 = pin1Params;
- innerWireParams.pin2 = pin2Params;
- innerWireParams.path = innerWire.getPath();
- i1++;
- }
- submodelParams.innerWires = wireParams;
-
- SubmodelComponentParams params = new SubmodelComponentParams();
- params.submodel = submodelParams;
+ SubmodelComponentParams params = new SubmodelComponentParams(CURRENT_JSON_VERSION);
+ params.innerScale = comp.getSubmodelScale();
+ params.submodel = ViewModelSerializer.serialize(comp.submodel, idGetter);
params.width = comp.getWidth();
params.height = comp.getHeight();
--- /dev/null
+package net.mograsim.logic.model.serializing;
+
+import com.google.gson.JsonElement;
+
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.mograsim.logic.model.util.Version;
+
+public class ViewModelParams extends SerializablePojo
+{
+ public ComponentParams[] components;
+ public WireParams[] wires;
+
+ public ViewModelParams(Version version)
+ {
+ super(version);
+ }
+
+ public static class ComponentParams
+ {
+ public String id;
+ public String name;
+ public Point pos;
+ public JsonElement params;
+ }
+
+ public static class WireParams
+ {
+ public PinParams pin1, pin2;
+ public String name;
+ public Point[] path;
+
+ public static class PinParams
+ {
+ public String compName;
+ public String pinName;
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+package net.mograsim.logic.model.serializing;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import com.google.gson.JsonElement;
+
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.mograsim.logic.model.model.ViewModel;
+import net.mograsim.logic.model.model.ViewModelModifiable;
+import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.model.wires.GUIWire;
+import net.mograsim.logic.model.serializing.ViewModelParams.ComponentParams;
+import net.mograsim.logic.model.serializing.ViewModelParams.WireParams;
+import net.mograsim.logic.model.serializing.ViewModelParams.WireParams.PinParams;
+import net.mograsim.logic.model.util.JsonHandler;
+import net.mograsim.logic.model.util.Version;
+
+public class ViewModelSerializer
+{
+ public static final Version CURRENT_JSON_VERSION = Version.parseSemver("0.1.1");
+
+ // convenience methods
+ /**
+ * Like {@link #deserialize(ViewModelParams)}, but first reading the {@link ViewModelParams} from the given file path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static ViewModelModifiable deserialize(String sourcePath) throws IOException
+ {
+ return deserialize(JsonHandler.readJson(sourcePath, ViewModelParams.class));
+ }
+
+ /**
+ * Like {@link #deserialize(ViewModelModifiable, ViewModelParams)}, but first reading the {@link ViewModelParams} from the given file
+ * path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static void deserialize(ViewModelModifiable model, String sourcePath) throws IOException
+ {
+ deserialize(model, JsonHandler.readJson(sourcePath, ViewModelParams.class));
+ }
+
+ /**
+ * Like {@link #deserialize(ViewModelModifiable, ViewModelParams)}, but using a newly created {@link ViewModelModifiable}.
+ *
+ * @author Daniel Kirschten
+ */
+ public static ViewModelModifiable deserialize(ViewModelParams params)
+ {
+ ViewModelModifiable model = new ViewModelModifiable();
+ deserialize(model, params);
+ return model;
+ }
+
+ /**
+ * Like {@link #serialize(ViewModel)}, but instead of returning the generated {@link ViewModelParams} they are written to a file at the
+ * given path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static void serialize(ViewModel model, String targetPath) throws IOException
+ {
+ JsonHandler.writeJson(serialize(model), targetPath);
+ }
+
+ /**
+ * Like {@link #serialize(ViewModel, IdentifierGetter)}, but instead of returning the generated {@link ViewModelParams} they are written
+ * to a file at the given path.
+ *
+ * @author Daniel Kirschten
+ */
+ public static void serialize(ViewModel model, IdentifierGetter idGetter, String targetPath) throws IOException
+ {
+ JsonHandler.writeJson(serialize(model, idGetter), targetPath);
+ }
+
+ /**
+ * {@link #serialize(ViewModel, IdentifierGetter)} using a default {@link IdentifierGetter} (see <code>IdentifierGetter</code>'s
+ * {@link IdentifierGetter#IdentifierGetter() default constructor})
+ *
+ * @author Daniel Kirschten
+ */
+ public static ViewModelParams serialize(ViewModel model)
+ {
+ return serialize(model, new IdentifierGetter());
+ }
+
+ // "core" methods
+ /**
+ * Deserializes components and wires from the specified {@link ViewModelParams} and adds them to the given {@link ViewModelModifiable}.
+ *
+ * @author Fabian Stemmler
+ * @author Daniel Kirschten
+ */
+ @SuppressWarnings("unused") // for GUIWire being created
+ public static void deserialize(ViewModelModifiable model, ViewModelParams params)
+ {
+ Map<String, GUIComponent> componentsByName = model.getComponentsByName();
+ GUIComponent[] components = new GUIComponent[params.components.length];
+ for (int i = 0; i < components.length; i++)
+ {
+ ComponentParams compParams = params.components[i];
+ components[i] = IndirectGUIComponentCreator.createComponent(model, compParams.id, compParams.params, compParams.name);
+ components[i].moveTo(compParams.pos.x, compParams.pos.y);
+ }
+
+ for (int i = 0; i < params.wires.length; i++)
+ {
+ WireParams wire = params.wires[i];
+ new GUIWire(model, wire.name, componentsByName.get(wire.pin1.compName).getPin(wire.pin1.pinName),
+ componentsByName.get(wire.pin2.compName).getPin(wire.pin2.pinName), wire.path);
+ }
+ }
+
+ /**
+ * Returns {@link ViewModelModifiable}, which describe the components and wires in the given {@link ViewModel}. <br>
+ * Components are serialized in the following way: <br>
+ * If a component is a <code>SubmodelComponent</code> which has been deserialized, and it has an
+ * {@link DeserializedSubmodelComponent#idForSerializingOverride idForSerializingOverride} set (e.g. non-null; see
+ * {@link SubmodelComponentSerializer#deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)
+ * SubmodelComponentSerializer.deserialize(...)}), this ID and the component's
+ * {@link DeserializedSubmodelComponent#paramsForSerializingOverride paramsForSerializingOverride} are written.<br>
+ * If this case doesn't apply (e.g. if the component is not a <code>SubmodelComponent</code>; or it is a <code>SubmodelComponent</code>,
+ * but hasn't been deserialized; or it has no {@link DeserializedSubmodelComponent#idForSerializingOverride idForSerializingOverride}
+ * set), the ID defined by <code>idGetter</code> and the params obtained by {@link GUIComponent#getParamsForSerializing() getParams()}
+ * are written.
+ *
+ * @author Fabian Stemmler
+ * @author Daniel Kirschten
+ */
+ public static ViewModelParams serialize(ViewModel model, IdentifierGetter idGetter)
+ {
+ ViewModelParams modelParams = new ViewModelParams(CURRENT_JSON_VERSION);
+
+ Map<String, GUIComponent> components = new HashMap<>(model.getComponentsByName());
+ components.remove(SubmodelComponent.SUBMODEL_INTERFACE_NAME);
+ Set<ComponentParams> componentsParams = new HashSet<>();
+ for (GUIComponent component : components.values())
+ {
+ ComponentParams compParams = new ComponentParams();
+ componentsParams.add(compParams);
+ compParams.pos = new Point(component.getPosX(), component.getPosY());
+ DeserializedSubmodelComponent innerCompCasted;
+ if (component instanceof DeserializedSubmodelComponent
+ && (innerCompCasted = (DeserializedSubmodelComponent) component).idForSerializingOverride != null)
+ {
+ compParams.id = innerCompCasted.idForSerializingOverride;
+ compParams.params = innerCompCasted.paramsForSerializingOverride;
+ } else
+ {
+ compParams.id = idGetter.componentIDs.apply(component);
+ compParams.params = component.getParamsForSerializing(idGetter);
+ }
+ compParams.name = component.name;
+ }
+ modelParams.components = componentsParams.toArray(ComponentParams[]::new);
+
+ Collection<GUIWire> wires = model.getWiresByName().values();
+ Set<WireParams> wiresParams = new HashSet<>();
+ for (GUIWire innerWire : wires)
+ {
+ WireParams innerWireParams = new WireParams();
+ wiresParams.add(innerWireParams);
+ PinParams pin1Params = new PinParams(), pin2Params = new PinParams();
+
+ pin1Params.pinName = innerWire.getPin1().name;
+ pin1Params.compName = innerWire.getPin1().component.name;
+ pin2Params.pinName = innerWire.getPin2().name;
+ pin2Params.compName = innerWire.getPin2().component.name;
+ innerWireParams.name = innerWire.name;
+ innerWireParams.pin1 = pin1Params;
+ innerWireParams.pin2 = pin2Params;
+ innerWireParams.path = innerWire.getPath();
+ }
+ modelParams.wires = wiresParams.toArray(WireParams[]::new);
+
+ return modelParams;
+ }
+}
\ No newline at end of file
public class JsonHandler
{
- // TODO: write versions differently
- private static Gson parser = new GsonBuilder().setPrettyPrinting().create();
+ public final static Gson parser = new GsonBuilder().setPrettyPrinting().create();
public static <T> T readJson(String path, Class<T> type) throws IOException
{
public static <T> T fromJson(String src, Class<T> type)
{
- // TODO actually parse and compare version
+ // throw away legacy version line
String rawJson = src.lines().dropWhile(s -> s.length() == 0 || s.charAt(0) != '{').collect(Collectors.joining());
return parser.fromJson(rawJson, type);
}
public static String toJson(Object o)
{
- return String.format("mograsim version: %s\n%s", Version.jsonCompVersion.toString(), parser.toJson(o));
+ return parser.toJson(o);
}
public static JsonElement toJsonTree(Object o)
package net.mograsim.logic.model.util;
+import java.io.IOException;
+
+import com.google.gson.TypeAdapter;
+import com.google.gson.annotations.JsonAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import net.mograsim.logic.model.util.Version.VersionJSONAdapter;
+
+@JsonAdapter(VersionJSONAdapter.class)
public final class Version
{
- public final static Version jsonCompVersion = new Version(0, 1, 3);
public final int major, minor, patch;
public Version(int major, int minor, int patch)
@Override
public String toString()
+ {
+ return toSemverString();
+ }
+
+ public String toSemverString()
{
return major + "." + minor + "." + patch;
}
+ public static Version parseSemver(String semver)
+ {
+ String[] semverParts = semver.split("\\.");
+ return new Version(Integer.parseInt(semverParts[0]), semverParts.length > 1 ? Integer.parseInt(semverParts[1]) : 0,
+ semverParts.length > 2 ? Integer.parseInt(semverParts[2]) : 0);
+ }
+
@Override
public int hashCode()
{
public boolean is(int major)
{
- return major != this.major;
+ return major == this.major;
}
public boolean is(int major, int minor)
{
return is(major, minor) && this.patch == patch;
}
+
+ static class VersionJSONAdapter extends TypeAdapter<Version>
+ {
+ @Override
+ public void write(JsonWriter out, Version value) throws IOException
+ {
+ out.value(value.toSemverString());
+ }
+
+ @Override
+ public Version read(JsonReader in) throws IOException
+ {
+ return parseSemver(in.nextString());
+ }
+ }
}
\ No newline at end of file