1 package net.mograsim.logic.model.serializing;
3 import java.io.IOException;
4 import java.util.Collection;
5 import java.util.HashMap;
7 import java.util.function.Function;
9 import com.google.gson.Gson;
10 import com.google.gson.JsonElement;
12 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
13 import net.mograsim.logic.model.model.ViewModelModifiable;
14 import net.mograsim.logic.model.model.components.GUIComponent;
15 import net.mograsim.logic.model.model.components.submodels.SimpleRectangularSubmodelComponent;
16 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
17 import net.mograsim.logic.model.model.wires.GUIWire;
18 import net.mograsim.logic.model.model.wires.MovablePin;
19 import net.mograsim.logic.model.model.wires.Pin;
20 import net.mograsim.logic.model.serializing.SubmodelComponentParams.InterfacePinParams;
21 import net.mograsim.logic.model.serializing.SubmodelComponentParams.SubmodelParameters;
22 import net.mograsim.logic.model.serializing.SubmodelComponentParams.SubmodelParameters.InnerComponentParams;
23 import net.mograsim.logic.model.serializing.SubmodelComponentParams.SubmodelParameters.InnerWireParams;
24 import net.mograsim.logic.model.serializing.SubmodelComponentParams.SubmodelParameters.InnerWireParams.InnerPinParams;
25 import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
26 import net.mograsim.logic.model.snippets.symbolrenderers.SimpleRectangularLikeSymbolRenderer.SimpleRectangularLikeParams;
27 import net.mograsim.logic.model.util.JsonHandler;
30 * Creates {@link SubmodelComponent}s from {@link SubmodelComponentParams}
32 * @author Fabian Stemmler
33 * @author Daniel Kirschten
35 public final class SubmodelComponentSerializer
37 // convenience methods
40 * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams)}, but first reading the {@link SubmodelComponentParams} from
41 * the given file path.
43 * @author Daniel Kirschten
45 public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath) throws IOException
47 return deserialize(model, JsonHandler.readJson(sourcePath, SubmodelComponentParams.class));
51 * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, JsonElement)}, but first reading the
52 * {@link SubmodelComponentParams} from the given file path.
54 * @author Daniel Kirschten
56 public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath, String idForSerializingOverride,
57 JsonElement paramsForSerializingOverride) throws IOException
59 return deserialize(model, JsonHandler.readJson(sourcePath, SubmodelComponentParams.class), idForSerializingOverride,
60 paramsForSerializingOverride);
64 * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String)}, but first reading the
65 * {@link SubmodelComponentParams} from the given file path.
67 * @author Daniel Kirschten
69 public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath, String name) throws IOException
71 return deserialize(model, JsonHandler.readJson(sourcePath, SubmodelComponentParams.class), name);
75 * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)}, but first reading the
76 * {@link SubmodelComponentParams} from the given file path.
78 * @author Daniel Kirschten
80 public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath, String name, String idForSerializingOverride,
81 JsonElement paramsForSerializingOverride) throws IOException
83 return deserialize(model, JsonHandler.readJson(sourcePath, SubmodelComponentParams.class), name, idForSerializingOverride,
84 paramsForSerializingOverride);
88 * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)} with no
89 * <code>idForSerializingOverride</code> set and using the default name.
91 * @author Daniel Kirschten
93 public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params)
95 return deserialize(model, params, null, null, null);
99 * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)} using the default name.
101 * @author Daniel Kirschten
103 public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params, String idForSerializingOverride,
104 JsonElement paramsForSerializingOverride)
106 return deserialize(model, params, null, idForSerializingOverride, paramsForSerializingOverride);
110 * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)} with no
111 * <code>idForSerializingOverride</code> set.
113 * @author Daniel Kirschten
115 public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params, String name)
117 return deserialize(model, params, name, null, null);
121 * Like {@link #serialize(SubmodelComponent)}, but instead of returning the generated {@link SubmodelComponentParams} they are written
122 * to a file at the given path.
124 * @author Daniel Kirschten
126 public static void serialize(SubmodelComponent comp, String targetPath) throws IOException
128 JsonHandler.writeJson(serialize(comp), targetPath);
132 * Like {@link #serialize(SubmodelComponent, Function)}, but instead of returning the generated {@link SubmodelComponentParams} they are
133 * written to a file at the given path.
135 * @author Daniel Kirschten
137 public static void serialize(SubmodelComponent comp, Function<GUIComponent, String> getIdentifier, String targetPath) throws IOException
139 JsonHandler.writeJson(serialize(comp, getIdentifier), targetPath);
143 * {@link #serialize(SubmodelComponent, Function)} using <code>"class:"</code> concatenated with a component's complete (canonical)
144 * class name for the ID of a component.
146 * @author Daniel Kirschten
148 public static SubmodelComponentParams serialize(SubmodelComponent comp)
150 return serialize(comp, c -> "class:" + c.getClass().getCanonicalName());
155 * Creates a {@link SubmodelComponent} from the specified {@link SubmodelComponentParams} with the given name.
157 * When serializing a <code>SubmodelComponent</code>, it is undesired for every subcomponent to be serialized with its complete inner
158 * structure. Instead, these sub-<code>SubmodelComponent</code>s should be serialized with the ID and params which were used to
159 * determine the <code>SubmodelComponentParams</code> defining the sub-<code>SubmodelComponent</code>. Because of this, it is possible
160 * to override the ID and params used in {@link #serialize(SubmodelComponent, Function) serialize(...)} to describe this subcomponent.
161 * See there for details.
163 * @author Fabian Stemmler
164 * @author Daniel Kirschten
166 @SuppressWarnings("unused") // for GUIWire being created
167 public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params, String name,
168 String idForSerializingOverride, JsonElement paramsForSerializingOverride)
170 DeserializedSubmodelComponent comp = new DeserializedSubmodelComponent(model, name, idForSerializingOverride,
171 paramsForSerializingOverride);
172 comp.setSubmodelScale(params.submodel.innerScale);
173 comp.setSymbolRenderer(SubmodelComponentSnippetSuppliers.symbolRendererSupplier.getSnippetSupplier(params.symbolRendererSnippetID)
174 .create(comp, params.symbolRendererParams));
175 comp.setOutlineRenderer(SubmodelComponentSnippetSuppliers.outlineRendererSupplier
176 .getSnippetSupplier(params.outlineRendererSnippetID).create(comp, params.outlineRendererParams));
177 comp.setHighLevelStateHandler(SubmodelComponentSnippetSuppliers.highLevelStateHandlerSupplier
178 .getSnippetSupplier(params.highLevelStateHandlerSnippetID).create(comp, params.highLevelStateHandlerParams));
179 comp.setSize(params.width, params.height);
180 for (InterfacePinParams iPinParams : params.interfacePins)
181 comp.addSubmodelInterface(
182 new MovablePin(comp, iPinParams.name, iPinParams.logicWidth, iPinParams.location.x, iPinParams.location.y));
183 SubmodelParameters submodelParams = params.submodel;
184 ViewModelModifiable submodelModifiable = comp.getSubmodelModifiable();
185 Map<String, GUIComponent> componentsByName = submodelModifiable.getComponentsByName();
186 GUIComponent[] components = new GUIComponent[submodelParams.subComps.length];
187 for (int i = 0; i < components.length; i++)
189 InnerComponentParams cParams = submodelParams.subComps[i];
190 components[i] = IndirectGUIComponentCreator.createComponent(submodelModifiable, cParams.id, cParams.params, cParams.name);
191 components[i].moveTo(cParams.pos.x, cParams.pos.y);
194 for (int i = 0; i < submodelParams.innerWires.length; i++)
196 InnerWireParams innerWire = submodelParams.innerWires[i];
197 new GUIWire(submodelModifiable, innerWire.name, componentsByName.get(innerWire.pin1.compName).getPin(innerWire.pin1.pinName),
198 componentsByName.get(innerWire.pin2.compName).getPin(innerWire.pin2.pinName), innerWire.path);
204 * Returns {@link SubmodelComponentParams}, which describe this {@link SubmodelComponent}. <br>
205 * Subcomponents are serialized in the following way: <br>
206 * If a subcomponent is a <code>SubmodelComponent</code> which has been deserialized, and it has an
207 * {@link DeserializedSubmodelComponent#idForSerializingOverride idForSerializingOverride} set (e.g. non-null; see
208 * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement) deserialize(...)}), this ID and the
209 * component's {@link DeserializedSubmodelComponent#paramsForSerializingOverride paramsForSerializingOverride} are written.<br>
210 * If this case doesn't apply (e.g. if the subcomponent is not a <code>SubmodelComponent</code>; or it is a
211 * <code>SubmodelComponent</code>, but hasn't been deserialized; or it has no
212 * {@link DeserializedSubmodelComponent#idForSerializingOverride idForSerializingOverride} set), the ID returned by
213 * <code>getIdentifier</code> and the params obtained by {@link GUIComponent#getParamsForSerializing() getParams()} are written.
215 * @author Fabian Stemmler
216 * @author Daniel Kirschten
218 public static SubmodelComponentParams serialize(SubmodelComponent comp, Function<GUIComponent, String> getIdentifier)
220 SubmodelParameters submodelParams = new SubmodelParameters();
221 submodelParams.innerScale = comp.getSubmodelScale();
223 Map<String, GUIComponent> components = new HashMap<>(comp.submodel.getComponentsByName());
224 components.remove(SubmodelComponent.SUBMODEL_INTERFACE_NAME);
225 InnerComponentParams[] componentParams = new InnerComponentParams[components.size()];
227 for (GUIComponent innerComponent : components.values())
229 InnerComponentParams innerComponentParams = new InnerComponentParams();
230 componentParams[i1] = innerComponentParams;
231 innerComponentParams.pos = new Point(innerComponent.getPosX(), innerComponent.getPosY());
232 DeserializedSubmodelComponent innerCompCasted;
233 if (innerComponent instanceof DeserializedSubmodelComponent
234 && (innerCompCasted = (DeserializedSubmodelComponent) innerComponent).idForSerializingOverride != null)
236 innerComponentParams.id = innerCompCasted.idForSerializingOverride;
237 innerComponentParams.params = innerCompCasted.paramsForSerializingOverride;
240 innerComponentParams.id = getIdentifier.apply(innerComponent);
241 innerComponentParams.params = innerComponent.getParamsForSerializing();
243 innerComponentParams.name = innerComponent.name;
246 submodelParams.subComps = componentParams;
248 Collection<GUIWire> wires = comp.submodel.getWiresByName().values();
249 InnerWireParams wireParams[] = new InnerWireParams[wires.size()];
251 for (GUIWire innerWire : wires)
253 InnerWireParams innerWireParams = new InnerWireParams();
254 wireParams[i1] = innerWireParams;
255 InnerPinParams pin1Params = new InnerPinParams(), pin2Params = new InnerPinParams();
257 pin1Params.pinName = innerWire.getPin1().name;
258 pin1Params.compName = innerWire.getPin1().component.name;
259 pin2Params.pinName = innerWire.getPin2().name;
260 pin2Params.compName = innerWire.getPin2().component.name;
261 innerWireParams.name = innerWire.name;
262 innerWireParams.pin1 = pin1Params;
263 innerWireParams.pin2 = pin2Params;
264 innerWireParams.path = innerWire.getPath();
267 submodelParams.innerWires = wireParams;
269 SubmodelComponentParams params = new SubmodelComponentParams();
270 params.submodel = submodelParams;
272 params.width = comp.getWidth();
273 params.height = comp.getHeight();
275 InterfacePinParams[] iPins = new InterfacePinParams[comp.getPins().size()];
277 for (Pin p : comp.getPins().values())
279 InterfacePinParams iPinParams = new InterfacePinParams();
280 iPins[i] = iPinParams;
281 iPinParams.location = p.getRelPos();
282 iPinParams.name = p.name;
283 iPinParams.logicWidth = p.logicWidth;
286 params.interfacePins = iPins;
288 // TODO This code does not belong here
289 if (comp instanceof SimpleRectangularSubmodelComponent)
291 SimpleRectangularSubmodelComponent compCasted = (SimpleRectangularSubmodelComponent) comp;
293 SimpleRectangularLikeParams symbolRendererParams = new SimpleRectangularLikeParams();
294 symbolRendererParams.centerText = compCasted.label;
295 symbolRendererParams.centerTextHeight = SimpleRectangularSubmodelComponent.labelFontHeight;
296 symbolRendererParams.horizontalComponentCenter = compCasted.getWidth() / 2;
297 symbolRendererParams.pinLabelHeight = SimpleRectangularSubmodelComponent.pinNameFontHeight;
298 symbolRendererParams.pinLabelMargin = SimpleRectangularSubmodelComponent.pinNameMargin;
300 params.symbolRendererSnippetID = "simpleRectangularLike";
301 params.symbolRendererParams = new Gson().toJsonTree(symbolRendererParams);