Restructured serializing/deserializing
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 15 Jul 2019 09:42:19 +0000 (11:42 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 15 Jul 2019 09:42:19 +0000 (11:42 +0200)
43 files changed:
net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/examples/ComponenetSerializer.java
net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/examples/JsonExample.java
net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/examples/SubmodelComponentTestbench.java
net.mograsim.logic.model/META-INF/MANIFEST.MF
net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/GUIComponent.java
net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/atomic/SimpleRectangularGUIGate.java
net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/atomic/TextComponent.java
net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/submodels/SimpleRectangularSubmodelComponent.java
net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/submodels/SubmodelComponent.java
net.mograsim.logic.model/src/net/mograsim/logic/model/model/wires/WireCrossPoint.java
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/CodeSnippetSupplier.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/DeserializedSubmodelComponent.java
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/IndirectGUIComponentCreator.java
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/SubmodelComponentDeserializer.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/SubmodelComponentParams.java
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/SubmodelComponentSerializer.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/HighLevelStateHandler.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/Renderer.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/SnippetSupplier.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/highlevelstatehandlers/DefaultHighLevelStateHandler.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/outlinerenderers/DefaultOutlineRenderer.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/symbolrenderers/CenteredTextSymbolRenderer.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/symbolrenderers/DefaultSymbolRenderer.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/symbolrenderers/SimpleRectangularLikeSymbolRenderer.java [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/standardSnippetIDMapping.json [deleted file]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/CodeSnippetSupplier.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/HighLevelStateHandler.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/Renderer.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/SnippetDefinintion.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/SubmodelComponentSnippetSuppliers.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/DefaultHighLevelStateHandler.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/HighLevelStateHandlerContext.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/StandardHighLevelStateHandler.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/StandardHighLevelStateHandlerSnippetSuppliers.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/atomic/AtomicHighLevelStateHandler.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/standardSnippetIDMapping.json [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/subcomponent/SubcomponentHighLevelStateHandler.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/outlinerenderers/DefaultOutlineRenderer.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/standardSnippetIDMapping.json [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/symbolrenderers/CenteredTextSymbolRenderer.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/symbolrenderers/DefaultSymbolRenderer.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/symbolrenderers/SimpleRectangularLikeSymbolRenderer.java [new file with mode: 0644]
net.mograsim.logic.model/src/net/mograsim/logic/model/util/JsonHandler.java

index 3d568e3..00478d4 100644 (file)
@@ -36,6 +36,7 @@ import net.mograsim.logic.model.model.components.mi.nandbased.am2901.GUIAm2901QR
 import net.mograsim.logic.model.model.components.mi.nandbased.am2901.GUIAm2901SourceDecode;
 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
 import net.mograsim.logic.model.serializing.SubmodelComponentParams;
+import net.mograsim.logic.model.serializing.SubmodelComponentSerializer;
 import net.mograsim.logic.model.util.JsonHandler;
 
 public class ComponenetSerializer
@@ -56,7 +57,7 @@ public class ComponenetSerializer
 
                for (SubmodelComponent comp : components)
                {
-                       SubmodelComponentParams params = comp.calculateParams(getIdentifier);
+                       SubmodelComponentParams params = SubmodelComponentSerializer.serialize(comp, getIdentifier);
                        JsonHandler.writeJson(params, "components/"
                                        + comp.getClass().getName().substring("net.mograsim.logic.ui.model.components.mi.nandbased.".length()).replace('.', '/')
                                        + ".json");
index 120ceb6..5f95c3e 100644 (file)
@@ -1,6 +1,7 @@
 package net.mograsim.logic.model.examples;
 
 import java.io.IOException;
+import java.io.UncheckedIOException;
 
 import com.google.gson.JsonNull;
 
@@ -14,7 +15,7 @@ import net.mograsim.logic.model.model.components.submodels.SimpleRectangularSubm
 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
 import net.mograsim.logic.model.model.wires.GUIWire;
 import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;
-import net.mograsim.logic.model.serializing.SubmodelComponentDeserializer;
+import net.mograsim.logic.model.serializing.SubmodelComponentSerializer;
 import net.mograsim.logic.model.serializing.SubmodelComponentParams;
 import net.mograsim.logic.model.util.JsonHandler;
 
@@ -37,7 +38,14 @@ public class JsonExample
                        super(model, 1, "Test", name);
                        setSubmodelScale(.4);
                        setInputPins("Input pin #0");
-                       SubmodelComponentDeserializer.create(submodelModifiable, "HalfAdder.json", "halfadder");
+                       try
+                       {
+                               SubmodelComponentSerializer.deserialize(submodelModifiable, "HalfAdder.json", "halfadder");
+                       }
+                       catch (IOException e)
+                       {
+                               throw new UncheckedIOException(e);
+                       }
                }
        }
 
@@ -46,11 +54,11 @@ public class JsonExample
        {
                GUI_rsLatch comp = new GUI_rsLatch(viewModel, "Original RS latch");
                comp.moveTo(30, 0);
-               SubmodelComponentParams params = comp.calculateParams();
+               SubmodelComponentParams params = SubmodelComponentSerializer.serialize(comp);
                String jsonString = JsonHandler.toJson(params);
                System.out.println(jsonString);
                SubmodelComponentParams paramsD = JsonHandler.fromJson(jsonString, SubmodelComponentParams.class);
-               SubmodelComponent componentD = SubmodelComponentDeserializer.create(viewModel, paramsD, "Deserialized RS latch");
+               SubmodelComponent componentD = SubmodelComponentSerializer.deserialize(viewModel, paramsD, "Deserialized RS latch");
                componentD.moveTo(30, 50);
                double h = 0;
                for (String s : comp.getInputPinNames())
@@ -80,8 +88,16 @@ public class JsonExample
        public static void refJsonFromJsonTest(ViewModelModifiable model)
        {
                TestComponent t = new TestComponent(model, "Original component");
-               t.calculateParams().writeJson("Test.json");
-               SubmodelComponent c = SubmodelComponentDeserializer.create(model, "Test.json", "Deserialized component");
+               SubmodelComponentSerializer.serialize(t).writeJson("Test.json");
+               SubmodelComponent c;
+               try
+               {
+                       c = SubmodelComponentSerializer.deserialize(model, "Test.json", "Deserialized component");
+               }
+               catch (IOException e)
+               {
+                       throw new UncheckedIOException(e);
+               }
                c.moveTo(0, 50);
        }
 
@@ -89,7 +105,7 @@ public class JsonExample
        public static void createFromJsonExample(ViewModelModifiable model)
        {
                SimpleRectangularSubmodelComponent tmp = new GUIfulladder(model, "Original full adder");
-               SubmodelComponentParams pC = tmp.calculateParams();
+               SubmodelComponentParams pC = SubmodelComponentSerializer.serialize(tmp);
                tmp.moveTo(1000, 100);
                try
                {
@@ -101,8 +117,16 @@ public class JsonExample
                        e.printStackTrace();
                }
 
-               SimpleRectangularSubmodelComponent adder = (SimpleRectangularSubmodelComponent) SubmodelComponentDeserializer.create(model,
-                               "FullAdder.json", "Deserialized full adder");
+               SimpleRectangularSubmodelComponent adder;
+               try
+               {
+                       adder = (SimpleRectangularSubmodelComponent) SubmodelComponentSerializer.deserialize(model, "FullAdder.json",
+                                       "Deserialized full adder");
+               }
+               catch (IOException e)
+               {
+                       throw new UncheckedIOException(e);
+               }
 
                GUIManualSwitch swA = new GUIManualSwitch(model);
                swA.moveTo(0, 0);
@@ -124,7 +148,7 @@ public class JsonExample
                new GUIWire(model, adder.getPin("Y"), bdY.getInputPin());
                new GUIWire(model, adder.getPin("Z"), bdZ.getInputPin());
 
-               SubmodelComponent adder2 = SubmodelComponentDeserializer.create(model, pC, "Full adder created from params instance");
+               SubmodelComponent adder2 = SubmodelComponentSerializer.deserialize(model, pC, "Full adder created from params instance");
 
                swA = new GUIManualSwitch(model);
                swA.moveTo(0, 70);
index 0d9c604..6a42d70 100644 (file)
@@ -1,5 +1,7 @@
 package net.mograsim.logic.model.examples;
 
+import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -10,7 +12,7 @@ import net.mograsim.logic.model.model.components.atomic.GUIManualSwitch;
 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
 import net.mograsim.logic.model.model.wires.GUIWire;
 import net.mograsim.logic.model.model.wires.Pin;
-import net.mograsim.logic.model.serializing.SubmodelComponentDeserializer;
+import net.mograsim.logic.model.serializing.SubmodelComponentSerializer;
 
 public class SubmodelComponentTestbench
 {
@@ -22,7 +24,15 @@ public class SubmodelComponentTestbench
        @SuppressWarnings("unused") // for GUIWires being created
        public static void createTestbench(ViewModelModifiable model)
        {
-               SubmodelComponent comp = SubmodelComponentDeserializer.create(model, "components/am2901/GUIAm2901.json");
+               SubmodelComponent comp;
+               try
+               {
+                       comp = SubmodelComponentSerializer.deserialize(model, "components/am2901/GUIAm2901.json");
+               }
+               catch (IOException e)
+               {
+                       throw new UncheckedIOException(e);
+               }
 
                // guess which pins are outputs and which are inputs
                // TODO this code exists three times... but it seems too "hacky" to put it in a helper class
index 61a85d1..6da2e2a 100644 (file)
@@ -13,10 +13,13 @@ Export-Package: net.mograsim.logic.model,
  net.mograsim.logic.model.modeladapter,
  net.mograsim.logic.model.modeladapter.componentadapters,
  net.mograsim.logic.model.serializing,
- net.mograsim.logic.model.serializing.snippets,
- net.mograsim.logic.model.serializing.snippets.highlevelstatehandlers,
- net.mograsim.logic.model.serializing.snippets.outlinerenderers,
- net.mograsim.logic.model.serializing.snippets.symbolrenderers,
+ net.mograsim.logic.model.snippets,
+ net.mograsim.logic.model.snippets.highlevelstatehandlers,
+ net.mograsim.logic.model.snippets.highlevelstatehandlers.standard,
+ net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic,
+ net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.subcomponent,
+ net.mograsim.logic.model.snippets.outlinerenderers,
+ net.mograsim.logic.model.snippets.symbolrenderers,
  net.mograsim.logic.model.util
 Bundle-RequiredExecutionEnvironment: JavaSE-11
 Require-Bundle: org.eclipse.swt;bundle-version="3.0.0";visibility:=reexport,
index 1b97cd3..4baf335 100644 (file)
@@ -14,11 +14,13 @@ import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 import net.mograsim.logic.model.model.ViewModelModifiable;
 import net.mograsim.logic.model.model.wires.Pin;
-import net.mograsim.logic.model.serializing.snippets.HighLevelStateHandler;
+import net.mograsim.logic.model.snippets.HighLevelStateHandler;
 
 /**
  * The base class for all GUI components.<br>
- * A <code>GUIComponent</code> has a position and size. The size can only be modified by subclasses.<br>
+ * A <code>GUIComponent</code> has a reference to the ViewModel it belongs to.<br>
+ * A <code>GUIComponent</code> has a name. This name is unique in the model the <code>GUIComponent</code> belongs to.<br>
+ * A <code>GUIComponent</code> has a position and size. The size can only be modified by subclasses.
  * 
  * @author Daniel Kirschten
  */
@@ -148,7 +150,7 @@ public abstract class GUIComponent
 
        /**
         * Sets the given high-level state to the given value. <br>
-        * See {@link HighLevelStateHandler#setHighLevelState(String, Object)} for an explanation of high-level state IDs.
+        * See {@link HighLevelStateHandler} for an explanation of high-level state IDs.
         * 
         * @see #getHighLevelState(String)
         * @see HighLevelStateHandler#setHighLevelState(String, Object)
@@ -163,7 +165,7 @@ public abstract class GUIComponent
 
        /**
         * Gets the current value of the given high-level state. <br>
-        * See {@link HighLevelStateHandler#setHighLevelState(String, Object)} for an explanation of high-level state IDs.
+        * See {@link HighLevelStateHandler} for an explanation of high-level state IDs.
         * 
         * @see #setHighLevelState(String, Object)
         * @see HighLevelStateHandler#getHighLevelState(String)
@@ -277,7 +279,7 @@ public abstract class GUIComponent
        // serializing
 
        @SuppressWarnings("static-method") // this method is intended to be overridden
-       public JsonElement getParams()
+       public JsonElement getParamsForSerializing()
        {
                return JsonNull.INSTANCE;
        }
index c7c2607..9535d3b 100644 (file)
@@ -91,10 +91,10 @@ public class SimpleRectangularGUIGate extends GUIComponent
         * {@link SimpleRectangularGUIGate}s implementation returns a {@link JsonPrimitive} of type int containing the {@link #logicWidth} of
         * this component.
         * 
-        * @see GUIComponent#getParams()
+        * @see GUIComponent#getParamsForSerializing()
         */
        @Override
-       public JsonElement getParams()
+       public JsonElement getParamsForSerializing()
        {
                return new JsonPrimitive(logicWidth);
        }
index 64a6165..87c3cf4 100644 (file)
@@ -49,7 +49,7 @@ public class TextComponent extends GUIComponent
        // serializing
 
        @Override
-       public JsonElement getParams()
+       public JsonElement getParamsForSerializing()
        {
                return new JsonPrimitive(text);
        }
index 530f078..039cdab 100644 (file)
@@ -5,33 +5,28 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
-import java.util.function.Function;
 
 import org.eclipse.swt.graphics.Color;
 
-import com.google.gson.JsonObject;
-
 import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 import net.mograsim.logic.model.model.ViewModelModifiable;
-import net.mograsim.logic.model.model.components.GUIComponent;
 import net.mograsim.logic.model.model.wires.MovablePin;
 import net.mograsim.logic.model.model.wires.Pin;
-import net.mograsim.logic.model.serializing.SubmodelComponentParams;
-import net.mograsim.logic.model.serializing.snippets.Renderer;
-import net.mograsim.logic.model.serializing.snippets.symbolrenderers.SimpleRectangularLikeSymbolRenderer;
-import net.mograsim.logic.model.serializing.snippets.symbolrenderers.SimpleRectangularLikeSymbolRenderer.SimpleRectangularLikeParams;
+import net.mograsim.logic.model.snippets.Renderer;
+import net.mograsim.logic.model.snippets.symbolrenderers.SimpleRectangularLikeSymbolRenderer;
+import net.mograsim.logic.model.snippets.symbolrenderers.SimpleRectangularLikeSymbolRenderer.SimpleRectangularLikeParams;
 import net.mograsim.preferences.Preferences;
 
 public class SimpleRectangularSubmodelComponent extends SubmodelComponent
 {
-       private static final double width = 35;
-       private static final double pinDistance = 10;
-       private static final double pinNameMargin = .5;
-       private static final double labelFontHeight = 5;
-       private static final double pinNameFontHeight = 3.5;
+       public static final double width = 35;
+       public static final double pinDistance = 10;
+       public static final double pinNameMargin = .5;
+       public static final double labelFontHeight = 5;
+       public static final double pinNameFontHeight = 3.5;
 
-       private final String label;
+       public final String label;
        protected final int logicWidth;
 
        private final List<String> inputPinNames;
@@ -126,23 +121,6 @@ public class SimpleRectangularSubmodelComponent extends SubmodelComponent
                gc.drawRectangle(getBounds());
        }
 
-       // serializing
-
-       @Override
-       public SubmodelComponentParams calculateParams(Function<GUIComponent, String> getIdentifier)
-       {
-               SubmodelComponentParams params = super.calculateParams(getIdentifier);
-               JsonObject symbolRendererParams = new JsonObject();
-               symbolRendererParams.addProperty("centerText", label);
-               symbolRendererParams.addProperty("horizontalComponentCenter", getWidth() / 2);
-               symbolRendererParams.addProperty("centerTextHeight", labelFontHeight);
-               symbolRendererParams.addProperty("pinLabelHeight", pinNameFontHeight);
-               symbolRendererParams.addProperty("pinLabelMargin", pinNameMargin);
-               params.symbolRendererSnippetID = "SimpleRectangularLikeSymbolRenderer";
-               params.symbolRendererParams = symbolRendererParams;
-               return params;
-       }
-
        @Override
        protected Pin addSubmodelInterface(MovablePin supermodelPin)
        {
index b19f05d..b5c1762 100644 (file)
@@ -2,39 +2,28 @@ package net.mograsim.logic.model.model.components.submodels;
 
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
-import java.util.function.Function;
 
 import net.haspamelodica.swt.helper.gcs.GCConfig;
 import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.gcs.TranslatedGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 import net.mograsim.logic.model.LogicUIRenderer;
 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.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;
-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;
 
 /**
  * A {@link GUIComponent} consisting of another model. A <code>SubmodelComponent</code> can have so-called "interface pins" connecting the
  * inner and outer models.
  */
+//TODO override getParams
 public abstract class SubmodelComponent extends GUIComponent
 {
-       private static final String SUBMODEL_INTERFACE_NAME = "_submodelinterface";
+       public static final String SUBMODEL_INTERFACE_NAME = "_submodelinterface";
        /**
         * A modifiable view of {@link #submodel}.
         */
@@ -72,15 +61,6 @@ public abstract class SubmodelComponent extends GUIComponent
         */
        private final SubmodelInterface submodelInterface;
 
-       /**
-        * The list of all high level state IDs this component supports without delegating to subcomponents.
-        */
-       private final Set<String> highLevelAtomicStates;
-       /**
-        * A map of high level state subcomponent IDs to the {@link GUIComponent} high level state access requests are delegated to.
-        */
-       private final Map<String, GUIComponent> subcomponentsByHighLevelStateSubcomponentID;
-
        /**
         * The factor by which the submodel is scaled when rendering.
         */
@@ -115,9 +95,6 @@ public abstract class SubmodelComponent extends GUIComponent
                this.supermodelUnmovablePinsUnmodifiable = Collections.unmodifiableMap(supermodelPins);
                this.submodelInterface = new SubmodelInterface(submodelModifiable, SUBMODEL_INTERFACE_NAME);
 
-               this.highLevelAtomicStates = new HashSet<>();
-               this.subcomponentsByHighLevelStateSubcomponentID = new HashMap<>();
-
                this.submodelScale = 1;
                this.maxVisibleRegionFillRatioForAlpha0 = 0.4;
                this.minVisibleRegionFillRatioForAlpha1 = 0.8;
@@ -264,153 +241,6 @@ public abstract class SubmodelComponent extends GUIComponent
                return supermodelPins.get(name);
        }
 
-       // high-level access
-
-       /**
-        * Adds the given subcomponent ID to the set of allowed subcomponent IDs and links the given {@link GUIComponent} as the delegate target
-        * for this subcomponent ID. <br>
-        * Note that this method does not affect whether {@link #setSubcomponentHighLevelState(String, String, Object)
-        * set}/{@link #getSubcomponentHighLevelState(String, String)} will be called. <br>
-        * See {@link GUIComponent#setHighLevelState(String, Object)} for details about subcomponent IDs.
-        * 
-        * @author Daniel Kirschten
-        */
-       protected void addHighLevelStateSubcomponentID(String subcomponentID, GUIComponent subcomponent)
-       {
-               checkHighLevelStateIDPart(subcomponentID);
-               subcomponentsByHighLevelStateSubcomponentID.put(subcomponentID, subcomponent);
-       }
-
-       /**
-        * Removes the given subcomponent ID from the set of allowed subcomponent IDs. <br>
-        * Note that this method does not affect whether {@link #setSubcomponentHighLevelState(String, String, Object)
-        * set}/{@link #getSubcomponentHighLevelState(String, String)} will be called.<br>
-        * See {@link GUIComponent#setHighLevelState(String, Object)} for details about subcomponent IDs.
-        * 
-        * @author Daniel Kirschten
-        */
-       protected void removeHighLevelStateSubcomponentID(String subcomponentID)
-       {
-               subcomponentsByHighLevelStateSubcomponentID.remove(subcomponentID);
-       }
-
-       /**
-        * Adds the given atomic state ID to the set of allowed atomic state IDs. <br>
-        * See {@link GUIComponent#setHighLevelState(String, Object)} for details about atomic state IDs.
-        * 
-        * @author Daniel Kirschten
-        */
-       protected void addAtomicHighLevelStateID(String stateID)
-       {
-               checkHighLevelStateIDPart(stateID);
-               highLevelAtomicStates.add(stateID);
-       }
-
-       /**
-        * Removes the given atomic state ID from the set of allowed atomic state IDs. <br>
-        * See {@link GUIComponent#setHighLevelState(String, Object)} for details about atomic state IDs.
-        * 
-        * @author Daniel Kirschten
-        */
-       protected void removeAtomicHighLevelStateID(String stateID)
-       {
-               highLevelAtomicStates.remove(stateID);
-       }
-
-       @Override
-       public final void setHighLevelState(String stateID, Object newState)
-       {
-               int indexOfDot = stateID.indexOf('.');
-               if (indexOfDot == -1)
-                       if (highLevelAtomicStates.contains(stateID))
-                               setAtomicHighLevelState(stateID, newState);
-                       else
-                               super.setHighLevelState(stateID, newState);
-               else
-                       setSubcomponentHighLevelState(stateID.substring(0, indexOfDot), stateID.substring(indexOfDot + 1), newState);
-       }
-
-       /**
-        * This method is called in {@link #setHighLevelState(String, Object)} when the state ID is not atomic. The default implementation uses
-        * the information given to {@link #addHighLevelStateSubcomponentID(String, GUIComponent)
-        * add}/{@link #removeHighLevelStateSubcomponentID(String)} to decide which subcomponent to delegate to.<br>
-        * Note that {@link #addHighLevelStateSubcomponentID(String, GUIComponent) add}/{@link #removeHighLevelStateSubcomponentID(String)}
-        * don't affect whether this method will be called.
-        * 
-        * @author Daniel Kirschten
-        */
-       protected void setSubcomponentHighLevelState(String subcomponentID, String subcomponentHighLevelStateID, Object newState)
-       {
-               GUIComponent subcomponent = subcomponentsByHighLevelStateSubcomponentID.get(subcomponentID);
-               if (subcomponent != null)
-                       subcomponent.setHighLevelState(subcomponentHighLevelStateID, newState);
-               else
-                       super.setHighLevelState(subcomponentID + "." + subcomponentHighLevelStateID, newState);
-       }
-
-       /**
-        * This method is called in {@link #setHighLevelState(String, Object)} when the state ID is atomic and in the set of allowed atomic
-        * state IDs. <br>
-        * See {@link GUIComponent#setHighLevelState(String, Object)} for details about atomic state IDs.
-        * 
-        * @author Daniel Kirschten
-        */
-       @SuppressWarnings({ "static-method", "unused" }) // this method is intended to be overridden
-       protected void setAtomicHighLevelState(String stateID, Object newState)
-       {
-               throw new IllegalStateException("Unknown high level state ID: " + stateID);
-       }
-
-       @Override
-       public final Object getHighLevelState(String stateID)
-       {
-               int indexOfDot = stateID.indexOf('.');
-               if (indexOfDot == -1)
-               {
-                       if (highLevelAtomicStates.contains(stateID))
-                               return getAtomicHighLevelState(stateID);
-                       return super.getHighLevelState(stateID);
-               }
-               return getSubcomponentHighLevelState(stateID.substring(0, indexOfDot), stateID.substring(indexOfDot + 1));
-       }
-
-       /**
-        * This method is called in {@link #getHighLevelState(String, Object)} when the state ID is not atomic. The default implementation uses
-        * the information given to {@link #addHighLevelStateSubcomponentID(String, GUIComponent)
-        * add}/{@link #removeHighLevelStateSubcomponentID(String)} to decide which subcomponent to delegate to. <br>
-        * Note that {@link #addHighLevelStateSubcomponentID(String, GUIComponent) add}/{@link #removeHighLevelStateSubcomponentID(String)}
-        * don't affect whether this method will be called.
-        * 
-        * @author Daniel Kirschten
-        */
-       protected Object getSubcomponentHighLevelState(String subcomponentID, String subcomponentHighLevelStateID)
-       {
-               GUIComponent subcomponent = subcomponentsByHighLevelStateSubcomponentID.get(subcomponentID);
-               if (subcomponent != null)
-                       return subcomponent.getHighLevelState(subcomponentHighLevelStateID);
-               return super.getHighLevelState(subcomponentID + "." + subcomponentHighLevelStateID);
-       }
-
-       /**
-        * This method is called in {@link SubmodelComponent#getHighLevelState(String)} when the state ID is in the set of allowed atomic state
-        * IDs. <br>
-        * See {@link GUIComponent#setHighLevelState(String, Object)} for details about atomic state IDs.
-        * 
-        * @author Daniel Kirschten
-        */
-       @SuppressWarnings("static-method") // this method is intended to be overridden
-       protected Object getAtomicHighLevelState(String stateID)
-       {
-               throw new IllegalStateException("Unknown high level state ID: " + stateID);
-       }
-
-       private static void checkHighLevelStateIDPart(String stateIDPart)
-       {
-               if (stateIDPart.indexOf('.') != -1)
-                       throw new IllegalArgumentException("Illegal high level state ID part (contains dot): " + stateIDPart);
-
-       }
-
        // "graphical" operations
 
        /**
@@ -434,7 +264,7 @@ public abstract class SubmodelComponent extends GUIComponent
         * 
         * @author Daniel Kirschten
         */
-       protected double getSubmodelScale()
+       public double getSubmodelScale()
        {
                return submodelScale;
        }
@@ -498,84 +328,6 @@ public abstract class SubmodelComponent extends GUIComponent
                return false;
        }
 
-       // serializing
-
-       // TODO move the methods below to serializing classes
-
-       public SubmodelComponentParams calculateParams()
-       {
-               return calculateParams(c -> "class:" + c.getClass().getCanonicalName());
-       }
-
-       /**
-        * @return {@link SubmodelComponentParams}, which describe this {@link SubmodelComponent}.
-        */
-       public SubmodelComponentParams calculateParams(Function<GUIComponent, String> getIdentifier)
-       {
-               SubmodelComponentParams params = new SubmodelComponentParams();
-               params.submodel = calculateSubmodelParams(getIdentifier);
-
-               params.width = getWidth();
-               params.height = getHeight();
-
-               InterfacePinParams[] iPins = new InterfacePinParams[getPins().size()];
-               int i = 0;
-               for (Pin p : getPins().values())
-               {
-                       InterfacePinParams iPinParams = new InterfacePinParams();
-                       iPins[i] = iPinParams;
-                       iPinParams.location = p.getRelPos();
-                       iPinParams.name = p.name;
-                       iPinParams.logicWidth = p.logicWidth;
-                       i++;
-               }
-               params.interfacePins = iPins;
-               return params;
-       }
-
-       private SubmodelParameters calculateSubmodelParams(Function<GUIComponent, String> getIdentifier)
-       {
-               SubmodelParameters params = new SubmodelParameters();
-               params.innerScale = getSubmodelScale();
-
-               Map<String, GUIComponent> components = new HashMap<>(submodel.getComponentsByName());
-               components.remove(SUBMODEL_INTERFACE_NAME);
-               InnerComponentParams[] comps = new InnerComponentParams[components.size()];
-               int i = 0;
-               for (GUIComponent component : components.values())
-               {
-                       InnerComponentParams inner = new InnerComponentParams();
-                       comps[i] = inner;
-                       inner.pos = new Point(component.getPosX(), component.getPosY());
-                       inner.id = getIdentifier.apply(component);
-                       inner.params = component.getParams();
-                       inner.name = component.name;
-                       i++;
-               }
-               params.subComps = comps;
-
-               List<GUIWire> wireList = submodel.getWires();
-               InnerWireParams wires[] = new InnerWireParams[wireList.size()];
-               i = 0;
-               for (GUIWire wire : wireList)
-               {
-                       InnerWireParams inner = new InnerWireParams();
-                       wires[i] = inner;
-                       InnerPinParams pin1Params = new InnerPinParams(), pin2Params = new InnerPinParams();
-
-                       pin1Params.pinName = wire.getPin1().name;
-                       pin1Params.compName = wire.getPin1().component.name;
-                       pin2Params.pinName = wire.getPin2().name;
-                       pin2Params.compName = wire.getPin2().component.name;
-                       inner.pin1 = pin1Params;
-                       inner.pin2 = pin2Params;
-                       inner.path = wire.getPath();
-                       i++;
-               }
-               params.innerWires = wires;
-               return params;
-       }
-
        // operations no longer supported
 
        @Override
index 52db277..f7150a2 100644 (file)
@@ -115,7 +115,7 @@ public class WireCrossPoint extends GUIComponent
        // serializing
 
        @Override
-       public JsonElement getParams()
+       public JsonElement getParamsForSerializing()
        {
                return new JsonPrimitive(pin.logicWidth);
        }
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/CodeSnippetSupplier.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/CodeSnippetSupplier.java
deleted file mode 100644 (file)
index f9f151b..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-package net.mograsim.logic.model.serializing;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Map;
-
-import net.mograsim.logic.model.serializing.snippets.HighLevelStateHandler;
-import net.mograsim.logic.model.serializing.snippets.Renderer;
-import net.mograsim.logic.model.serializing.snippets.SnippetSupplier;
-import net.mograsim.logic.model.serializing.snippets.highlevelstatehandlers.DefaultHighLevelStateHandler;
-import net.mograsim.logic.model.serializing.snippets.outlinerenderers.DefaultOutlineRenderer;
-import net.mograsim.logic.model.serializing.snippets.symbolrenderers.DefaultSymbolRenderer;
-import net.mograsim.logic.model.util.JsonHandler;
-
-public class CodeSnippetSupplier<S>
-{
-       // public static members
-       public static final CodeSnippetSupplier<Renderer> symbolRendererSupplier;
-       public static final CodeSnippetSupplier<Renderer> outlineRendererSupplier;
-       public static final CodeSnippetSupplier<HighLevelStateHandler> highLevelStateHandlerSupplier;
-
-       static
-       {
-               symbolRendererSupplier = new CodeSnippetSupplier<>(SnippetSupplier.create(Void.class, DefaultSymbolRenderer::new));
-               outlineRendererSupplier = new CodeSnippetSupplier<>(SnippetSupplier.create(Void.class, DefaultOutlineRenderer::new));
-               highLevelStateHandlerSupplier = new CodeSnippetSupplier<>(SnippetSupplier.create(Void.class, DefaultHighLevelStateHandler::new));
-       }
-
-       // per-instance members
-
-       private final Map<String, String> standardSnippetIDClassNames = new HashMap<>();
-       private final Map<String, SnippetSupplier<?, S>> snippetSuppliersForClassNames = new HashMap<>();
-       private final SnippetSupplier<?, S> defaultSnippetSupplier;
-
-       private CodeSnippetSupplier(SnippetSupplier<?, S> defaultSnippetSupplier)
-       {
-               this.defaultSnippetSupplier = defaultSnippetSupplier;
-       }
-
-       public void addStandardSnippetID(String standardSnippetID, String associatedSnippetClassName)
-       {
-               standardSnippetIDClassNames.put(standardSnippetID, associatedSnippetClassName);
-       }
-
-       public void setSnippetSupplier(String id, SnippetSupplier<?, S> snippetSupplier)
-       {
-               snippetSuppliersForClassNames.put(id, snippetSupplier);
-       }
-
-       // TODO report errors
-       public SnippetSupplier<?, S> getSnippetSupplier(String id)
-       {
-               if (id != null)
-               {
-                       String snippetClassName;
-                       if (id.startsWith("class:"))
-                               snippetClassName = id.substring(6);
-                       else
-                               snippetClassName = standardSnippetIDClassNames.get(id);
-                       if (snippetClassName != null)
-                       {
-                               tryLoadSnippetClass(snippetClassName);
-                               SnippetSupplier<?, S> snippetSupplier = snippetSuppliersForClassNames.get(snippetClassName);
-                               if (snippetSupplier != null)
-                                       return snippetSupplier;
-                       }
-                       System.err.println("Couldn't load snippet " + id + "; using default");
-               }
-               return defaultSnippetSupplier;
-       }
-
-       // static helpers
-
-       static
-       {
-               try (InputStream s = IndirectGUIComponentCreator.class.getResourceAsStream("./standardSnippetIDMapping.json"))
-               {
-                       if (s == null)
-                               throw new IOException("Resource not found");
-                       SnippetIDClassNames tmp = JsonHandler.readJson(s, SnippetIDClassNames.class);
-                       tmp.standardOutlineRendererSuppliers.forEach(outlineRendererSupplier::addStandardSnippetID);
-                       tmp.standardSymbolRendererSuppliers.forEach(symbolRendererSupplier::addStandardSnippetID);
-                       tmp.standardHighLevelStateHandlerSuppliers.forEach(highLevelStateHandlerSupplier::addStandardSnippetID);
-               }
-               catch (Exception e)
-               {
-                       System.err.println("Failed to initialize standard snippet ID mapping: ");
-                       e.printStackTrace();
-               }
-       }
-
-       private static class SnippetIDClassNames
-       {
-               public Map<String, String> standardOutlineRendererSuppliers;
-               public Map<String, String> standardSymbolRendererSuppliers;
-               public Map<String, String> standardHighLevelStateHandlerSuppliers;
-       }
-
-       private static void tryLoadSnippetClass(String snippetClassName)
-       {
-               tryInvokeStaticInitializer(snippetClassName, "Error getting snippet class: %s: %s\n");
-       }
-
-       public static void tryInvokeStaticInitializer(String className, String errorMessageFormat)
-       {
-               try
-               {
-                       Class.forName(className, true, CodeSnippetSupplier.class.getClassLoader());
-               }
-               catch (ClassNotFoundException e)
-               {
-                       System.err.printf(errorMessageFormat, className, "ClassNotFoundException thrown: " + e.getMessage());
-               }
-       }
-
-}
\ No newline at end of file
index 1ec5144..8db85a1 100644 (file)
@@ -1,21 +1,53 @@
 package net.mograsim.logic.model.serializing;
 
+import com.google.gson.JsonElement;
+
 import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 import net.mograsim.logic.model.model.ViewModelModifiable;
 import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
 import net.mograsim.logic.model.model.wires.MovablePin;
 import net.mograsim.logic.model.model.wires.Pin;
-import net.mograsim.logic.model.serializing.snippets.Renderer;
+import net.mograsim.logic.model.snippets.HighLevelStateHandler;
+import net.mograsim.logic.model.snippets.Renderer;
 
 public class DeserializedSubmodelComponent extends SubmodelComponent
 {
-       public Renderer outlineRenderer;
-       public Renderer symbolRenderer;
+       /**
+        * If a DeserializedSubmodelComponent is part of another SubmodelComponent, when it it serialized, it should not return its internal
+        * structure, but rather the component ID used to create it.
+        * 
+        * @see SubmodelComponentSerializer#deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)
+        *      SubmodelComponentSerializer.deserialize(...)
+        * @see SubmodelComponentSerializer#serialize(SubmodelComponent, java.util.function.Function) SubmodelComponentSerializer.serialize(...)
+        */
+       public final String idForSerializingOverride;
+       /**
+        * See {@link #idForSerializingOverride}
+        */
+       public final JsonElement paramsForSerializingOverride;
+
+       private Renderer outlineRenderer;
+       private Renderer symbolRenderer;
+       private HighLevelStateHandler highLevelStateHandler;
 
-       public DeserializedSubmodelComponent(ViewModelModifiable model, String name)
+       public DeserializedSubmodelComponent(ViewModelModifiable model, String name, String idForSerializingOverride, JsonElement paramsForSerializingOverride)
        {
                super(model, name);
+               this.idForSerializingOverride = idForSerializingOverride;
+               this.paramsForSerializingOverride = paramsForSerializingOverride;
+       }
+
+       @Override
+       public void setHighLevelState(String stateID, Object newState)
+       {
+               highLevelStateHandler.setHighLevelState(stateID, newState);
+       }
+
+       @Override
+       public Object getHighLevelState(String stateID)
+       {
+               return highLevelStateHandler.getHighLevelState(stateID);
        }
 
        @Override
@@ -42,6 +74,11 @@ public class DeserializedSubmodelComponent extends SubmodelComponent
                this.symbolRenderer = symbolRenderer;
        }
 
+       public void setHighLevelStateHandler(HighLevelStateHandler highLevelStateHandler)
+       {
+               this.highLevelStateHandler = highLevelStateHandler;
+       }
+
        public ViewModelModifiable getSubmodelModifiable()
        {
                return submodelModifiable;
@@ -60,8 +97,10 @@ public class DeserializedSubmodelComponent extends SubmodelComponent
        }
 
        @Override
-       protected Pin addSubmodelInterface(MovablePin supermodelPin)
+       public Pin addSubmodelInterface(MovablePin supermodelPin)
        {
                return super.addSubmodelInterface(supermodelPin);
        }
+
+       // TODO static initializer
 }
\ No newline at end of file
index 874a8a8..a8f192e 100644 (file)
@@ -2,6 +2,7 @@ package net.mograsim.logic.model.serializing;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.UncheckedIOException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -10,6 +11,7 @@ import com.google.gson.JsonNull;
 
 import net.mograsim.logic.model.model.ViewModelModifiable;
 import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.snippets.CodeSnippetSupplier;
 import net.mograsim.logic.model.util.JsonHandler;
 
 public class IndirectGUIComponentCreator
@@ -88,9 +90,18 @@ public class IndirectGUIComponentCreator
                                if (componentSupplier != null)
                                        return componentSupplier.create(model, params, name);
                        } else
-                               // we know id has to start with "file:" here
-                               // because standardComponentIDs only contains strings starting with "class:" or "file:"
-                               return SubmodelComponentDeserializer.create(model, resolvedID.substring(5), name);
+                       // we know id has to start with "file:" here
+                       // because standardComponentIDs only contains strings starting with "class:" or "file:"
+                       if (params != null && !JsonNull.INSTANCE.equals(params))
+                               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);
+                       }
+                       catch (IOException e)
+                       {
+                               throw new UncheckedIOException(e);
+                       }
                }
                throw new RuntimeException("Could not get component supplier for ID " + id);
        }
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/SubmodelComponentDeserializer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/SubmodelComponentDeserializer.java
deleted file mode 100644 (file)
index a5e8793..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-package net.mograsim.logic.model.serializing;
-
-import java.io.IOException;
-import java.util.Map;
-
-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.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;
-
-/**
- * Creates {@link SubmodelComponent}s from {@link SubmodelComponentParams}
- */
-public final class SubmodelComponentDeserializer
-{
-       /**
-        * Like {@link #create(ViewModelModifiable, String, String)}, but using the default name.
-        */
-       public static SubmodelComponent create(ViewModelModifiable model, String path)
-       {
-               return create(model, path, null);
-       }
-
-       /**
-        * Creates a {@link SubmodelComponent} from the {@link SubmodelComponentParams} located at the given path as a JSON file. The returned
-        * SubmodelComponent is a {@link DeserializedSubmodelComponent}.
-        * 
-        * @param path The path of the file describing the {@link SubmodelComponentParams}, which define the new {@link SubmodelComponent}
-        * @return A new SubmodelComponent, as described in the file located at the given path
-        */
-       public static SubmodelComponent create(ViewModelModifiable model, String path, String name)
-       {
-               try
-               {
-                       SubmodelComponentParams params = SubmodelComponentParams.readJson(path);
-                       SubmodelComponent ret = create(model, params, name);
-                       return ret;
-               }
-               catch (IOException e)
-               {
-                       throw new RuntimeException("Failed to construct GUICustomComponent. Parameters were not found.", e);
-               }
-       }
-
-       /**
-        * Creates a {@link SubmodelComponent} from the specified {@link SubmodelComponentParams}. The returned SubmodelComponent is a
-        * {@link DeserializedSubmodelComponent}.
-        * 
-        * @param params The parameters describing the {@link SubmodelComponent}
-        * 
-        * @return A new SubmodelComponent, as described by the {@link SubmodelComponentParams}
-        */
-       public static SubmodelComponent create(ViewModelModifiable model, SubmodelComponentParams params, String name)
-       {
-               DeserializedSubmodelComponent comp = createSubmodelComponent(model, params, name);
-               initSubmodel(comp, params.submodel);
-               return comp;
-       }
-
-       private static DeserializedSubmodelComponent createSubmodelComponent(ViewModelModifiable model, SubmodelComponentParams params,
-                       String name)
-       {
-               DeserializedSubmodelComponent comp = new DeserializedSubmodelComponent(model, name);
-               comp.setSubmodelScale(params.submodel.innerScale);
-               comp.setOutlineRenderer(CodeSnippetSupplier.outlineRendererSupplier.getSnippetSupplier(params.outlineRendererSnippetID).create(comp,
-                               params.outlineRendererParams));
-               comp.setSymbolRenderer(CodeSnippetSupplier.symbolRendererSupplier.getSnippetSupplier(params.symbolRendererSnippetID).create(comp,
-                               params.symbolRendererParams));
-               // TODO high level states
-               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));
-               return comp;
-       }
-
-       @SuppressWarnings("unused") // GUIWire being created
-       private static void initSubmodel(DeserializedSubmodelComponent comp, SubmodelParameters params)
-       {
-               ViewModelModifiable submodelModifiable = comp.getSubmodelModifiable();
-               Map<String, GUIComponent> componentsByName = submodelModifiable.getComponentsByName();
-               GUIComponent[] components = new GUIComponent[params.subComps.length];
-               for (int i = 0; i < components.length; i++)
-               {
-                       InnerComponentParams cParams = params.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 < params.innerWires.length; i++)
-               {
-                       InnerWireParams innerWire = params.innerWires[i];
-                       new GUIWire(submodelModifiable, componentsByName.get(innerWire.pin1.compName).getPin(innerWire.pin1.pinName),
-                                       componentsByName.get(innerWire.pin2.compName).getPin(innerWire.pin2.pinName), innerWire.path);
-               }
-       }
-}
index afce226..49edfd6 100644 (file)
@@ -25,6 +25,9 @@ public class SubmodelComponentParams
        public String symbolRendererSnippetID;
        public JsonElement symbolRendererParams;
 
+       public String highLevelStateHandlerSnippetID;
+       public JsonElement highLevelStateHandlerParams;
+
        public static class InterfacePinParams
        {
                public Point location;
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/SubmodelComponentSerializer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/SubmodelComponentSerializer.java
new file mode 100644 (file)
index 0000000..7c002a0
--- /dev/null
@@ -0,0 +1,305 @@
+package net.mograsim.logic.model.serializing;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+import com.google.gson.Gson;
+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.SimpleRectangularSubmodelComponent;
+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.SubmodelComponentSnippetSuppliers;
+import net.mograsim.logic.model.snippets.symbolrenderers.SimpleRectangularLikeSymbolRenderer.SimpleRectangularLikeParams;
+import net.mograsim.logic.model.util.JsonHandler;
+
+/**
+ * Creates {@link SubmodelComponent}s from {@link SubmodelComponentParams}
+ * 
+ * @author Fabian Stemmler
+ * @author Daniel Kirschten
+ */
+public final class SubmodelComponentSerializer
+{
+       // convenience methods
+
+       /**
+        * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams)}, but first reading the {@link SubmodelComponentParams} from
+        * the given file path.
+        * 
+        * @author Daniel Kirschten
+        */
+       public static SubmodelComponent deserialize(ViewModelModifiable model, String sourcePath) throws IOException
+       {
+               return deserialize(model, JsonHandler.readJson(sourcePath, SubmodelComponentParams.class));
+       }
+
+       /**
+        * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, JsonElement)}, but first reading the
+        * {@link SubmodelComponentParams} 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, SubmodelComponentParams.class), idForSerializingOverride,
+                               paramsForSerializingOverride);
+       }
+
+       /**
+        * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String)}, but first reading the
+        * {@link SubmodelComponentParams} 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, SubmodelComponentParams.class), name);
+       }
+
+       /**
+        * Like {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)}, but first reading the
+        * {@link SubmodelComponentParams} 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, SubmodelComponentParams.class), name, idForSerializingOverride,
+                               paramsForSerializingOverride);
+       }
+
+       /**
+        * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)} with no
+        * <code>idForSerializingOverride</code> set and using the default name.
+        * 
+        * @author Daniel Kirschten
+        */
+       public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params)
+       {
+               return deserialize(model, params, null, null, null);
+       }
+
+       /**
+        * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)} using the default name.
+        * 
+        * @author Daniel Kirschten
+        */
+       public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params, String idForSerializingOverride,
+                       JsonElement paramsForSerializingOverride)
+       {
+               return deserialize(model, params, null, idForSerializingOverride, paramsForSerializingOverride);
+       }
+
+       /**
+        * {@link #deserialize(ViewModelModifiable, SubmodelComponentParams, String, String, JsonElement)} with no
+        * <code>idForSerializingOverride</code> set.
+        * 
+        * @author Daniel Kirschten
+        */
+       public static SubmodelComponent deserialize(ViewModelModifiable model, SubmodelComponentParams params, String name)
+       {
+               return deserialize(model, params, name, null, null);
+       }
+
+       /**
+        * Like {@link #serialize(SubmodelComponent)}, but instead of returning the generated {@link SubmodelComponentParams} 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 SubmodelComponentParams} they are
+        * written to a file at the given path.
+        * 
+        * @author Daniel Kirschten
+        */
+       public static void serialize(SubmodelComponent comp, Function<GUIComponent, String> getIdentifier, String targetPath) throws IOException
+       {
+               JsonHandler.writeJson(serialize(comp, getIdentifier), targetPath);
+       }
+
+       /**
+        * {@link #serialize(SubmodelComponent, Function)} using <code>"class:"</code> concatenated with a component's complete (canonical)
+        * class name for the ID of a component.
+        * 
+        * @author Daniel Kirschten
+        */
+       public static SubmodelComponentParams serialize(SubmodelComponent comp)
+       {
+               return serialize(comp, c -> "class:" + c.getClass().getCanonicalName());
+       }
+
+       // "core" methods
+       /**
+        * Creates a {@link SubmodelComponent} from the specified {@link SubmodelComponentParams} 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, SubmodelComponentParams params, String name,
+                       String idForSerializingOverride, JsonElement paramsForSerializingOverride)
+       {
+               DeserializedSubmodelComponent comp = new DeserializedSubmodelComponent(model, name, idForSerializingOverride,
+                               paramsForSerializingOverride);
+               comp.setSubmodelScale(params.submodel.innerScale);
+               comp.setOutlineRenderer(SubmodelComponentSnippetSuppliers.outlineRendererSupplier
+                               .getSnippetSupplier(params.outlineRendererSnippetID).create(comp, params.outlineRendererParams));
+               comp.setSymbolRenderer(SubmodelComponentSnippetSuppliers.symbolRendererSupplier.getSnippetSupplier(params.symbolRendererSnippetID)
+                               .create(comp, params.symbolRendererParams));
+               comp.setHighLevelStateHandler(SubmodelComponentSnippetSuppliers.highLevelStateHandlerSupplier
+                               .getSnippetSupplier(params.highLevelStateHandlerSnippetID).create(comp, params.highLevelStateHandlerParams));
+               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, componentsByName.get(innerWire.pin1.compName).getPin(innerWire.pin1.pinName),
+                                       componentsByName.get(innerWire.pin2.compName).getPin(innerWire.pin2.pinName), innerWire.path);
+               }
+               return comp;
+       }
+
+       /**
+        * 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 returned by
+        * <code>getIdentifier</code> and the params obtained by {@link GUIComponent#getParamsForSerializing() getParams()} are written.
+        * 
+        * @author Fabian Stemmler
+        * @author Daniel Kirschten
+        */
+       public static SubmodelComponentParams serialize(SubmodelComponent comp, Function<GUIComponent, String> getIdentifier)
+       {
+               SubmodelParameters submodelParams = new SubmodelParameters();
+               submodelParams.innerScale = comp.getSubmodelScale();
+
+               Map<String, GUIComponent> components = new HashMap<>(comp.submodel.getComponentsByName());
+               components.remove(SubmodelComponent.SUBMODEL_INTERFACE_NAME);
+               InnerComponentParams[] comps = new InnerComponentParams[components.size()];
+               int i1 = 0;
+               for (GUIComponent innerComp : components.values())
+               {
+                       InnerComponentParams innerParams = new InnerComponentParams();
+                       comps[i1] = innerParams;
+                       innerParams.pos = new Point(innerComp.getPosX(), innerComp.getPosY());
+                       DeserializedSubmodelComponent innerCompCasted;
+                       if (innerComp instanceof DeserializedSubmodelComponent
+                                       && (innerCompCasted = (DeserializedSubmodelComponent) innerComp).idForSerializingOverride != null)
+                       {
+                               innerParams.id = innerCompCasted.idForSerializingOverride;
+                               innerParams.params = innerCompCasted.paramsForSerializingOverride;
+                       } else
+                       {
+                               innerParams.id = getIdentifier.apply(innerComp);
+                               innerParams.params = innerComp.getParamsForSerializing();
+                       }
+                       innerParams.name = innerComp.name;
+                       i1++;
+               }
+               submodelParams.subComps = comps;
+
+               List<GUIWire> wireList = comp.submodel.getWires();
+               InnerWireParams wires[] = new InnerWireParams[wireList.size()];
+               i1 = 0;
+               for (GUIWire wire : wireList)
+               {
+                       InnerWireParams inner = new InnerWireParams();
+                       wires[i1] = inner;
+                       InnerPinParams pin1Params = new InnerPinParams(), pin2Params = new InnerPinParams();
+
+                       pin1Params.pinName = wire.getPin1().name;
+                       pin1Params.compName = wire.getPin1().component.name;
+                       pin2Params.pinName = wire.getPin2().name;
+                       pin2Params.compName = wire.getPin2().component.name;
+                       inner.pin1 = pin1Params;
+                       inner.pin2 = pin2Params;
+                       inner.path = wire.getPath();
+                       i1++;
+               }
+               submodelParams.innerWires = wires;
+
+               SubmodelComponentParams params = new SubmodelComponentParams();
+               params.submodel = submodelParams;
+
+               params.width = comp.getWidth();
+               params.height = comp.getHeight();
+
+               InterfacePinParams[] iPins = new InterfacePinParams[comp.getPins().size()];
+               int i = 0;
+               for (Pin p : comp.getPins().values())
+               {
+                       InterfacePinParams iPinParams = new InterfacePinParams();
+                       iPins[i] = iPinParams;
+                       iPinParams.location = p.getRelPos();
+                       iPinParams.name = p.name;
+                       iPinParams.logicWidth = p.logicWidth;
+                       i++;
+               }
+               params.interfacePins = iPins;
+
+               // TODO does this code belong here?
+               if (comp instanceof SimpleRectangularSubmodelComponent)
+               {
+                       SimpleRectangularSubmodelComponent compCasted = (SimpleRectangularSubmodelComponent) comp;
+
+                       SimpleRectangularLikeParams symbolRendererParams = new SimpleRectangularLikeParams();
+                       symbolRendererParams.centerText = compCasted.label;
+                       symbolRendererParams.centerTextHeight = SimpleRectangularSubmodelComponent.labelFontHeight;
+                       symbolRendererParams.horizontalComponentCenter = compCasted.getWidth() / 2;
+                       symbolRendererParams.pinLabelHeight = SimpleRectangularSubmodelComponent.pinNameFontHeight;
+                       symbolRendererParams.pinLabelMargin = SimpleRectangularSubmodelComponent.pinNameMargin;
+
+                       params.symbolRendererSnippetID = "SimpleRectangularLikeSymbolRenderer";
+                       params.symbolRendererParams = new Gson().toJsonTree(symbolRendererParams);
+               }
+
+               return params;
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/HighLevelStateHandler.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/HighLevelStateHandler.java
deleted file mode 100644 (file)
index f20b664..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-package net.mograsim.logic.model.serializing.snippets;
-
-import net.mograsim.logic.model.model.components.GUIComponent;
-
-public interface HighLevelStateHandler
-{
-       /**
-        * Sets the given high-level state to the given value. <br>
-        * A high level state ID consists of parts separated by dots ('.').<br>
-        * The last part (the part after the last dot) is called "atomic high level state ID". The parts before that part are called
-        * "subcomponent ID"s.<br>
-        * If there is no dot in a high level state ID, the whole high level state ID is called atomic.<br>
-        * Note that subcomponent IDs don't have to correspond to actual subcomponents. For example, a RAM component may supply subcomponent IDs
-        * "c0000", "c0001" ... "cFFFF" without actually having a subcomponent for each cell. It also is allowed to delegate an atomic high
-        * level state ID to a subcomponent.
-        * 
-        * @see #getHighLevelState(String)
-        * @see GUIComponent#setHighLevelState(String, Object)
-        * 
-        * @author Daniel Kirschten
-        */
-       public void setHighLevelState(String stateID, Object newState);
-
-       /**
-        * Gets the current value of the given high-level state. <br>
-        * See {@link #setHighLevelState(String, Object)} for an explanation of high-level state IDs.
-        * 
-        * @see #setHighLevelState(String, Object)
-        * @see GUIComponent#getHighLevelState(String)
-        * 
-        * @author Daniel Kirschten
-        */
-       public Object getHighLevelState(String stateID);
-}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/Renderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/Renderer.java
deleted file mode 100644 (file)
index 140780b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.mograsim.logic.model.serializing.snippets;
-
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-
-public interface Renderer
-{
-       public void render(GeneralGC gc, Rectangle visibleRegion);
-}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/SnippetSupplier.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/SnippetSupplier.java
deleted file mode 100644 (file)
index a2b71b5..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-package net.mograsim.logic.model.serializing.snippets;
-
-import java.util.function.BiFunction;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-
-import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-
-public interface SnippetSupplier<P, S>
-{
-       public Class<P> getParamClass();
-
-       public S create(SubmodelComponent component, P params);
-
-       public default S create(SubmodelComponent component, JsonElement params)
-       {
-               return create(component, new Gson().fromJson(params, getParamClass()));
-       }
-
-       public static <P, S> SnippetSupplier<P, S> create(Class<P> paramClass, BiFunction<SubmodelComponent, P, S> supplier)
-       {
-               return new SnippetSupplier<>()
-               {
-                       @Override
-                       public Class<P> getParamClass()
-                       {
-                               return paramClass;
-                       }
-
-                       @Override
-                       public S create(SubmodelComponent component, P params)
-                       {
-                               return supplier.apply(component, params);
-                       }
-               };
-       }
-}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/highlevelstatehandlers/DefaultHighLevelStateHandler.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/highlevelstatehandlers/DefaultHighLevelStateHandler.java
deleted file mode 100644 (file)
index eb08add..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-package net.mograsim.logic.model.serializing.snippets.highlevelstatehandlers;
-
-import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-import net.mograsim.logic.model.serializing.CodeSnippetSupplier;
-import net.mograsim.logic.model.serializing.snippets.HighLevelStateHandler;
-import net.mograsim.logic.model.serializing.snippets.SnippetSupplier;
-
-public class DefaultHighLevelStateHandler implements HighLevelStateHandler
-{
-       @SuppressWarnings("unused") // we don't need the component; and params are always null
-       public DefaultHighLevelStateHandler(SubmodelComponent component, Void params)
-       {
-               // nothing to do here
-       }
-
-       @Override
-       public void setHighLevelState(String stateID, Object newState)
-       {
-               throw new IllegalArgumentException("No high level state with ID " + stateID);
-       }
-
-       @Override
-       public Object getHighLevelState(String stateID)
-       {
-               throw new IllegalArgumentException("No high level state with ID " + stateID);
-       }
-
-       static
-       {
-               CodeSnippetSupplier.highLevelStateHandlerSupplier.setSnippetSupplier(DefaultHighLevelStateHandler.class.getCanonicalName(),
-                               SnippetSupplier.create(Void.class, DefaultHighLevelStateHandler::new));
-       }
-}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/outlinerenderers/DefaultOutlineRenderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/outlinerenderers/DefaultOutlineRenderer.java
deleted file mode 100644 (file)
index 3152864..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-package net.mograsim.logic.model.serializing.snippets.outlinerenderers;
-
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-import net.mograsim.logic.model.model.components.GUIComponent;
-import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-import net.mograsim.logic.model.serializing.CodeSnippetSupplier;
-import net.mograsim.logic.model.serializing.snippets.Renderer;
-import net.mograsim.logic.model.serializing.snippets.SnippetSupplier;
-import net.mograsim.preferences.ColorDefinition;
-import net.mograsim.preferences.ColorManager;
-import net.mograsim.preferences.Preferences;
-
-public class DefaultOutlineRenderer implements Renderer
-{
-       private final GUIComponent component;
-
-       public DefaultOutlineRenderer(SubmodelComponent component, @SuppressWarnings("unused") Void params)
-       {
-               this.component = component;
-       }
-
-       @Override
-       public void render(GeneralGC gc, Rectangle visibleRegion)
-       {
-               ColorDefinition fg = Preferences.current().getColorDefinition("net.mograsim.logic.ui.color.foreground");
-               if (fg != null)
-                       gc.setForeground(ColorManager.current().toColor(fg));
-               gc.drawRectangle(component.getBounds());
-       }
-
-       static
-       {
-               CodeSnippetSupplier.outlineRendererSupplier.setSnippetSupplier(DefaultOutlineRenderer.class.getCanonicalName(),
-                               SnippetSupplier.create(Void.class, DefaultOutlineRenderer::new));
-       }
-}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/symbolrenderers/CenteredTextSymbolRenderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/symbolrenderers/CenteredTextSymbolRenderer.java
deleted file mode 100644 (file)
index 9ccfa9c..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-package net.mograsim.logic.model.serializing.snippets.symbolrenderers;
-
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-import net.mograsim.logic.model.model.components.GUIComponent;
-import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-import net.mograsim.logic.model.serializing.CodeSnippetSupplier;
-import net.mograsim.logic.model.serializing.snippets.Renderer;
-import net.mograsim.logic.model.serializing.snippets.SnippetSupplier;
-import net.mograsim.preferences.ColorDefinition;
-import net.mograsim.preferences.ColorManager;
-import net.mograsim.preferences.Preferences;
-
-/**
- * Renders a text (<code>"text"</code>) with a given font height (<code>"height"</code>) in the center of the component.
- * 
- * @author Daniel Kirschten
- */
-public class CenteredTextSymbolRenderer implements Renderer
-{
-       private final GUIComponent component;
-       private final CenteredTextParams params;
-
-       public CenteredTextSymbolRenderer(SubmodelComponent component, CenteredTextParams params)
-       {
-               this.component = component;
-               this.params = params;
-
-       }
-
-       @Override
-       public void render(GeneralGC gc, Rectangle visibleRegion)
-       {
-               Font oldFont = gc.getFont();
-               gc.setFont(new Font(oldFont.getName(), params.fontHeight, oldFont.getStyle()));
-               ColorDefinition fg = Preferences.current().getColorDefinition("net.mograsim.logic.ui.color.text");
-               if (fg != null)
-                       gc.setForeground(ColorManager.current().toColor(fg));
-               Point idSize = gc.textExtent(params.text);
-               Rectangle bounds = component.getBounds();
-               gc.drawText(params.text, bounds.x + (bounds.width - idSize.x) / 2, bounds.y + (bounds.height - idSize.y) / 2, true);
-               gc.setFont(oldFont);
-       }
-
-       public static class CenteredTextParams
-       {
-               public String text;
-               public double fontHeight;
-       }
-
-       static
-       {
-               CodeSnippetSupplier.symbolRendererSupplier.setSnippetSupplier(CenteredTextSymbolRenderer.class.getCanonicalName(),
-                               SnippetSupplier.create(CenteredTextParams.class, CenteredTextSymbolRenderer::new));
-       }
-}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/symbolrenderers/DefaultSymbolRenderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/symbolrenderers/DefaultSymbolRenderer.java
deleted file mode 100644 (file)
index e6beadf..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.mograsim.logic.model.serializing.snippets.symbolrenderers;
-
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-import net.mograsim.logic.model.model.components.GUIComponent;
-import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-import net.mograsim.logic.model.serializing.CodeSnippetSupplier;
-import net.mograsim.logic.model.serializing.snippets.Renderer;
-import net.mograsim.logic.model.serializing.snippets.SnippetSupplier;
-import net.mograsim.preferences.ColorDefinition;
-import net.mograsim.preferences.ColorManager;
-import net.mograsim.preferences.Preferences;
-
-public class DefaultSymbolRenderer implements Renderer
-{
-       private static final String id = "<Symbol\nunknown>";
-
-       private final GUIComponent component;
-
-       public DefaultSymbolRenderer(SubmodelComponent component, @SuppressWarnings("unused") Void params)
-       {
-               this.component = component;
-       }
-
-       @Override
-       public void render(GeneralGC gc, Rectangle visibleRegion)
-       {
-               ColorDefinition fg = Preferences.current().getColorDefinition("net.mograsim.logic.ui.color.text");
-               if (fg != null)
-                       gc.setForeground(ColorManager.current().toColor(fg));
-               Point idSize = gc.textExtent(id);
-               Rectangle bounds = component.getBounds();
-               gc.drawText(id, bounds.x + (bounds.width - idSize.x) / 2, bounds.y + (bounds.height - idSize.y) / 2, true);
-       }
-
-       static
-       {
-               CodeSnippetSupplier.symbolRendererSupplier.setSnippetSupplier(DefaultSymbolRenderer.class.getCanonicalName(),
-                               SnippetSupplier.create(Void.class, DefaultSymbolRenderer::new));
-       }
-}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/symbolrenderers/SimpleRectangularLikeSymbolRenderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/snippets/symbolrenderers/SimpleRectangularLikeSymbolRenderer.java
deleted file mode 100644 (file)
index 30ab4bc..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-package net.mograsim.logic.model.serializing.snippets.symbolrenderers;
-
-import java.util.Map.Entry;
-
-import org.eclipse.swt.graphics.Color;
-
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-import net.mograsim.logic.model.model.components.GUIComponent;
-import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
-import net.mograsim.logic.model.model.wires.Pin;
-import net.mograsim.logic.model.serializing.CodeSnippetSupplier;
-import net.mograsim.logic.model.serializing.snippets.Renderer;
-import net.mograsim.logic.model.serializing.snippets.SnippetSupplier;
-import net.mograsim.preferences.Preferences;
-
-/**
- * Renders a text (<code>"centerText"</code>) with a given font height (<code>"centerTextHeight"</code>) in the center of the component and
- * draws a label for each pin with a given font height (<code>"pinLabelHeight"</code>). The labels of pins to the left of a given x
- * coordinate (<code>"horizontalComponentCenter"</code>) are drawn to the right of the respective pin; labels of pins to the right are drawn
- * left. A margin (<code>"pinLabelMargin"</code>) is applied for pin label drawing.
- * 
- * @author Daniel Kirschten
- */
-public class SimpleRectangularLikeSymbolRenderer implements Renderer
-{
-       private final GUIComponent component;
-       private final SimpleRectangularLikeParams params;
-
-       public SimpleRectangularLikeSymbolRenderer(SubmodelComponent component, SimpleRectangularLikeParams params)
-       {
-               this.component = component;
-               this.params = params;
-       }
-
-       @Override
-       public void render(GeneralGC gc, Rectangle visibleRegion)
-       {
-               double posX = component.getPosX();
-               double posY = component.getPosY();
-               double width = component.getWidth();
-               double height = component.getHeight();
-
-               Font oldFont = gc.getFont();
-               gc.setFont(new Font(oldFont.getName(), params.centerTextHeight, oldFont.getStyle()));
-               Point textExtent = gc.textExtent(params.centerText);
-               Color textColor = Preferences.current().getColor("net.mograsim.logic.ui.color.text");
-               if (textColor != null)
-                       gc.setForeground(textColor);
-               gc.drawText(params.centerText, posX + (width - textExtent.x) / 2, posY + (height - textExtent.y) / 2, true);
-               gc.setFont(new Font(oldFont.getName(), params.pinLabelHeight, oldFont.getStyle()));
-               for (Entry<String, Pin> pinEntry : component.getPins().entrySet())
-               {
-                       String pinName = pinEntry.getKey();
-                       Pin pin = pinEntry.getValue();
-                       double pinX = pin.getRelX();
-                       double pinY = posY + pin.getRelY();
-                       textExtent = gc.textExtent(pinName);
-                       gc.drawText(pinName,
-                                       posX + pinX + (pinX > params.horizontalComponentCenter ? -textExtent.x - params.pinLabelMargin : params.pinLabelMargin),
-                                       pinY - textExtent.y / 2, true);
-               }
-               gc.setFont(oldFont);
-       }
-
-       public static class SimpleRectangularLikeParams
-       {
-               public String centerText;
-               public double centerTextHeight;
-               public double horizontalComponentCenter;
-               public double pinLabelHeight;
-               public double pinLabelMargin;
-       }
-
-       static
-       {
-               CodeSnippetSupplier.symbolRendererSupplier.setSnippetSupplier(SimpleRectangularLikeSymbolRenderer.class.getCanonicalName(),
-                               SnippetSupplier.create(SimpleRectangularLikeParams.class, SimpleRectangularLikeSymbolRenderer::new));
-       }
-}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/standardSnippetIDMapping.json b/net.mograsim.logic.model/src/net/mograsim/logic/model/serializing/standardSnippetIDMapping.json
deleted file mode 100644 (file)
index db79c5f..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-mograsim version: 0.1.3
-{
-  "standardOutlineRendererSuppliers": {},
-  "standardSymbolRendererSuppliers": {
-    "CenteredTextSymbolRenderer": "net.mograsim.logic.model.serializing.snippets.symbolrenderers.CenteredTextSymbolRenderer",
-    "SimpleRectangularLikeSymbolRenderer": "net.mograsim.logic.model.serializing.snippets.symbolrenderers.SimpleRectangularLikeSymbolRenderer"
-  },
-  "standardHighLevelStateHandlerSuppliers": {}
-}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/CodeSnippetSupplier.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/CodeSnippetSupplier.java
new file mode 100644 (file)
index 0000000..86b5765
--- /dev/null
@@ -0,0 +1,70 @@
+package net.mograsim.logic.model.snippets;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class CodeSnippetSupplier<C, S>
+{
+       private final Map<String, String> standardSnippetIDClassNames = new HashMap<>();
+       private final Map<String, SnippetDefinintion<C, ?, S>> snippetSuppliersForClassNames = new HashMap<>();
+       private final SnippetDefinintion<C, ?, S> defaultSnippetSupplier;
+
+       public CodeSnippetSupplier(SnippetDefinintion<C, ?, S> defaultSnippetSupplier)
+       {
+               this.defaultSnippetSupplier = defaultSnippetSupplier;
+       }
+
+       public void addStandardSnippetID(String standardSnippetID, String associatedSnippetClassName)
+       {
+               standardSnippetIDClassNames.put(standardSnippetID, associatedSnippetClassName);
+       }
+
+       public void setSnippetSupplier(String id, SnippetDefinintion<C, ?, S> snippetSupplier)
+       {
+               snippetSuppliersForClassNames.put(id, snippetSupplier);
+       }
+
+       // TODO report errors
+       public SnippetDefinintion<C, ?, S> getSnippetSupplier(String id)
+       {
+               if (id != null)
+               {
+                       String snippetClassName;
+                       if (id.startsWith("class:"))
+                               snippetClassName = id.substring(6);
+                       else
+                               snippetClassName = standardSnippetIDClassNames.get(id);
+                       if (snippetClassName != null)
+                       {
+                               tryLoadSnippetClass(snippetClassName);
+                               SnippetDefinintion<C, ?, S> snippetSupplier = snippetSuppliersForClassNames.get(snippetClassName);
+                               if (snippetSupplier != null)
+                                       return snippetSupplier;
+                       }
+                       System.err.println("Couldn't load snippet " + id + "; using default");
+               }
+               if (defaultSnippetSupplier == null)
+                       throw new IllegalArgumentException("No default snippet set");
+               return defaultSnippetSupplier;
+       }
+
+       // static helpers
+
+       private static void tryLoadSnippetClass(String snippetClassName)
+       {
+               tryInvokeStaticInitializer(snippetClassName, "Error getting snippet class: %s: %s\n");
+       }
+
+       public static void tryInvokeStaticInitializer(String className, String errorMessageFormat)
+       {
+               try
+               {
+                       Class.forName(className, true, CodeSnippetSupplier.class.getClassLoader());
+               }
+               catch (ClassNotFoundException e)
+               {
+                       System.err.printf(errorMessageFormat, className, "ClassNotFoundException thrown: " + e.getMessage());
+               }
+       }
+
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/HighLevelStateHandler.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/HighLevelStateHandler.java
new file mode 100644 (file)
index 0000000..74f01d0
--- /dev/null
@@ -0,0 +1,40 @@
+package net.mograsim.logic.model.snippets;
+
+import net.mograsim.logic.model.model.components.GUIComponent;
+
+/**
+ * A high level state ID consists of parts separated by dots ('.').<br>
+ * The last part (the part after the last dot) is called "atomic high level state ID". The parts before that part are called "subcomponent
+ * ID"s.<br>
+ * If there is no dot in a high level state ID, the whole high level state ID is called atomic.<br>
+ * Note that subcomponent IDs don't have to correspond to actual subcomponents. For example, a RAM component may supply subcomponent IDs
+ * "c0000", "c0001" ... "cFFFF" without actually having a subcomponent for each cell. It also is allowed to delegate an atomic high level
+ * state ID to a subcomponent.
+ * 
+ * @author Daniel Kirschten
+ */
+public interface HighLevelStateHandler
+{
+       /**
+        * Gets the current value of the given high-level state. <br>
+        * See {@link HighLevelStateHandler} for an explanation of high-level state IDs.
+        * 
+        * @see #setHighLevelState(String, Object)
+        * @see GUIComponent#getHighLevelState(String)
+        * 
+        * @author Daniel Kirschten
+        */
+       public Object getHighLevelState(String stateID);
+
+       /**
+        * Sets the given high-level state to the given value. <br>
+        * See {@link HighLevelStateHandler} for an explanation of high-level state IDs.
+        * 
+        * @see #getHighLevelState(String)
+        * @see GUIComponent#setHighLevelState(String, Object)
+        * 
+        * @author Daniel Kirschten
+        */
+       public void setHighLevelState(String stateID, Object newState);
+
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/Renderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/Renderer.java
new file mode 100644 (file)
index 0000000..45a2c5e
--- /dev/null
@@ -0,0 +1,9 @@
+package net.mograsim.logic.model.snippets;
+
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+
+public interface Renderer
+{
+       public void render(GeneralGC gc, Rectangle visibleRegion);
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/SnippetDefinintion.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/SnippetDefinintion.java
new file mode 100644 (file)
index 0000000..77e715c
--- /dev/null
@@ -0,0 +1,36 @@
+package net.mograsim.logic.model.snippets;
+
+import java.util.function.BiFunction;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+
+public interface SnippetDefinintion<C, P, S>
+{
+       public Class<P> getParamClass();
+
+       public S create(C context, P params);
+
+       public default S create(C context, JsonElement params)
+       {
+               return create(context, new Gson().fromJson(params, getParamClass()));
+       }
+
+       public static <C, P, S> SnippetDefinintion<C, P, S> create(Class<P> paramClass, BiFunction<C, P, S> supplier)
+       {
+               return new SnippetDefinintion<>()
+               {
+                       @Override
+                       public Class<P> getParamClass()
+                       {
+                               return paramClass;
+                       }
+
+                       @Override
+                       public S create(C context, P params)
+                       {
+                               return supplier.apply(context, params);
+                       }
+               };
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/SubmodelComponentSnippetSuppliers.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/SubmodelComponentSnippetSuppliers.java
new file mode 100644 (file)
index 0000000..ff6e554
--- /dev/null
@@ -0,0 +1,55 @@
+package net.mograsim.logic.model.snippets;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.snippets.highlevelstatehandlers.DefaultHighLevelStateHandler;
+import net.mograsim.logic.model.snippets.outlinerenderers.DefaultOutlineRenderer;
+import net.mograsim.logic.model.snippets.symbolrenderers.DefaultSymbolRenderer;
+import net.mograsim.logic.model.util.JsonHandler;
+
+public class SubmodelComponentSnippetSuppliers
+{
+       public static final CodeSnippetSupplier<SubmodelComponent, Renderer> symbolRendererSupplier;
+       public static final CodeSnippetSupplier<SubmodelComponent, Renderer> outlineRendererSupplier;
+       public static final CodeSnippetSupplier<SubmodelComponent, HighLevelStateHandler> highLevelStateHandlerSupplier;
+
+       static
+       {
+               symbolRendererSupplier = new CodeSnippetSupplier<>(SnippetDefinintion.create(Void.class, DefaultSymbolRenderer::new));
+               outlineRendererSupplier = new CodeSnippetSupplier<>(SnippetDefinintion.create(Void.class, DefaultOutlineRenderer::new));
+               highLevelStateHandlerSupplier = new CodeSnippetSupplier<>(SnippetDefinintion.create(Void.class, DefaultHighLevelStateHandler::new));
+       }
+
+       static
+       {
+               try (InputStream s = SubmodelComponentSnippetSuppliers.class.getResourceAsStream("./standardSnippetIDMapping.json"))
+               {
+                       if (s == null)
+                               throw new IOException("Resource not found");
+                       SnippetIDClassNames tmp = JsonHandler.readJson(s, SnippetIDClassNames.class);
+                       tmp.standardOutlineRendererSuppliers.forEach(outlineRendererSupplier::addStandardSnippetID);
+                       tmp.standardSymbolRendererSuppliers.forEach(symbolRendererSupplier::addStandardSnippetID);
+                       tmp.standardHighLevelStateHandlerSuppliers.forEach(highLevelStateHandlerSupplier::addStandardSnippetID);
+               }
+               catch (Exception e)
+               {
+                       System.err.println("Failed to initialize standard snippet ID mapping:");
+                       e.printStackTrace();
+               }
+       }
+
+       private static class SnippetIDClassNames
+       {
+               public Map<String, String> standardOutlineRendererSuppliers;
+               public Map<String, String> standardSymbolRendererSuppliers;
+               public Map<String, String> standardHighLevelStateHandlerSuppliers;
+       }
+
+       private SubmodelComponentSnippetSuppliers()
+       {
+               throw new UnsupportedOperationException();
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/DefaultHighLevelStateHandler.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/DefaultHighLevelStateHandler.java
new file mode 100644 (file)
index 0000000..37c32d0
--- /dev/null
@@ -0,0 +1,34 @@
+package net.mograsim.logic.model.snippets.highlevelstatehandlers;
+
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.snippets.HighLevelStateHandler;
+import net.mograsim.logic.model.snippets.SnippetDefinintion;
+import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
+
+public class DefaultHighLevelStateHandler implements HighLevelStateHandler
+{
+       @SuppressWarnings("unused") // we don't need the component; and params are always null
+       public DefaultHighLevelStateHandler(SubmodelComponent component, Void params)
+       {
+               // nothing to do here
+       }
+
+       @Override
+       public Object getHighLevelState(String stateID)
+       {
+               throw new IllegalArgumentException("No high level state with ID " + stateID);
+       }
+
+       @Override
+       public void setHighLevelState(String stateID, Object newState)
+       {
+               throw new IllegalArgumentException("No high level state with ID " + stateID);
+       }
+
+       static
+       {
+               SubmodelComponentSnippetSuppliers.highLevelStateHandlerSupplier.setSnippetSupplier(
+                               DefaultHighLevelStateHandler.class.getCanonicalName(),
+                               SnippetDefinintion.create(Void.class, DefaultHighLevelStateHandler::new));
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/HighLevelStateHandlerContext.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/HighLevelStateHandlerContext.java
new file mode 100644 (file)
index 0000000..c5f8f13
--- /dev/null
@@ -0,0 +1,15 @@
+package net.mograsim.logic.model.snippets.highlevelstatehandlers.standard;
+
+import net.mograsim.logic.model.model.components.GUIComponent;
+
+public class HighLevelStateHandlerContext
+{
+       public final GUIComponent component;
+       public final String stateID;
+
+       public HighLevelStateHandlerContext(GUIComponent component, String stateID)
+       {
+               this.component = component;
+               this.stateID = stateID;
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/StandardHighLevelStateHandler.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/StandardHighLevelStateHandler.java
new file mode 100644 (file)
index 0000000..ec3b04d
--- /dev/null
@@ -0,0 +1,113 @@
+package net.mograsim.logic.model.snippets.highlevelstatehandlers.standard;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.snippets.HighLevelStateHandler;
+import net.mograsim.logic.model.snippets.SnippetDefinintion;
+import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
+import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic.AtomicHighLevelStateHandler;
+import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic.AtomicHighLevelStateHandler.AtomicHighLevelStateHandlerParams;
+import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.subcomponent.SubcomponentHighLevelStateHandler;
+import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.subcomponent.SubcomponentHighLevelStateHandler.SubcomponentHighLevelStateHandlerParams;
+
+public class StandardHighLevelStateHandler implements HighLevelStateHandler
+{
+       private final GUIComponent component;
+       private final Map<String, SubcomponentHighLevelStateHandler> subcomponentHighLevelStateHandlers;
+       private final Map<String, AtomicHighLevelStateHandler> atomicHighLevelStateHandlers;
+
+       public StandardHighLevelStateHandler(GUIComponent component, SimpleHighLevelStateHandlerParams params)
+       {
+               this.component = component;
+               this.subcomponentHighLevelStateHandlers = new HashMap<>();
+               this.atomicHighLevelStateHandlers = new HashMap<>();
+               params.subcomponentHighLevelStates.forEach(this::addSubcomponentHighLevelState);
+               params.atomicHighLevelStates.forEach(this::addAtomicHighLevelState);
+       }
+
+       public void addSubcomponentHighLevelState(String subcomponentStateID, SubcomponentHighLevelStateHandlerParams handlerParams)
+       {
+               HighLevelStateHandlerContext context = new HighLevelStateHandlerContext(component, subcomponentStateID);
+               addSubcomponentHighLevelState(subcomponentStateID, StandardHighLevelStateHandlerSnippetSuppliers.subcomponentHandlerSupplier
+                               .getSnippetSupplier(handlerParams.id).create(context, handlerParams.params));
+       }
+
+       public void addSubcomponentHighLevelState(String subcomponentStateID, SubcomponentHighLevelStateHandler handler)
+       {
+               checkHighLevelStateIDPart(subcomponentStateID);
+               subcomponentHighLevelStateHandlers.put(subcomponentStateID, handler);
+       }
+
+       public void addAtomicHighLevelState(String atomicStateID, AtomicHighLevelStateHandlerParams handlerParams)
+       {
+               HighLevelStateHandlerContext context = new HighLevelStateHandlerContext(component, atomicStateID);
+               addSubcomponentHighLevelState(atomicStateID, StandardHighLevelStateHandlerSnippetSuppliers.subcomponentHandlerSupplier
+                               .getSnippetSupplier(handlerParams.id).create(context, handlerParams.params));
+       }
+
+       public void addAtomicHighLevelState(String atomicStateID, AtomicHighLevelStateHandler handler)
+       {
+               checkHighLevelStateIDPart(atomicStateID);
+               atomicHighLevelStateHandlers.put(atomicStateID, handler);
+       }
+
+       private static void checkHighLevelStateIDPart(String stateIDPart)
+       {
+               if (stateIDPart.indexOf('.') != -1)
+                       throw new IllegalArgumentException("Illegal high level state ID part (contains dot): " + stateIDPart);
+       }
+
+       @Override
+       public Object getHighLevelState(String stateID)
+       {
+               int indexOfDot = stateID.indexOf('.');
+               if (indexOfDot == -1)
+               {
+                       AtomicHighLevelStateHandler handler = atomicHighLevelStateHandlers.get(stateID);
+                       if (handler != null)
+                               return handler.getHighLevelState();
+               } else
+               {
+                       SubcomponentHighLevelStateHandler handler = subcomponentHighLevelStateHandlers.get(stateID.substring(0, indexOfDot));
+                       if (handler != null)
+                               return handler.getHighLevelState(stateID.substring(indexOfDot + 1));
+               }
+               throw new IllegalArgumentException("No high level state with ID " + stateID);
+       }
+
+       @Override
+       public void setHighLevelState(String stateID, Object newState)
+       {
+               int indexOfDot = stateID.indexOf('.');
+               if (indexOfDot == -1)
+               {
+                       AtomicHighLevelStateHandler handler = atomicHighLevelStateHandlers.get(stateID);
+                       if (handler != null)
+                               handler.setHighLevelState(newState);
+                       else
+                               throw new IllegalArgumentException("No high level state with ID " + stateID);
+               } else
+               {
+                       SubcomponentHighLevelStateHandler handler = subcomponentHighLevelStateHandlers.get(stateID.substring(0, indexOfDot));
+                       if (handler != null)
+                               handler.setHighLevelState(stateID.substring(indexOfDot + 1), newState);
+                       else
+                               throw new IllegalArgumentException("No high level state with ID " + stateID);
+               }
+       }
+
+       public static class SimpleHighLevelStateHandlerParams
+       {
+               public Map<String, SubcomponentHighLevelStateHandlerParams> subcomponentHighLevelStates;
+               public Map<String, AtomicHighLevelStateHandlerParams> atomicHighLevelStates;
+       }
+
+       static
+       {
+               SubmodelComponentSnippetSuppliers.highLevelStateHandlerSupplier.setSnippetSupplier(
+                               StandardHighLevelStateHandler.class.getCanonicalName(),
+                               SnippetDefinintion.create(SimpleHighLevelStateHandlerParams.class, StandardHighLevelStateHandler::new));
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/StandardHighLevelStateHandlerSnippetSuppliers.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/StandardHighLevelStateHandlerSnippetSuppliers.java
new file mode 100644 (file)
index 0000000..e81607d
--- /dev/null
@@ -0,0 +1,50 @@
+package net.mograsim.logic.model.snippets.highlevelstatehandlers.standard;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+import net.mograsim.logic.model.snippets.CodeSnippetSupplier;
+import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic.AtomicHighLevelStateHandler;
+import net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.subcomponent.SubcomponentHighLevelStateHandler;
+import net.mograsim.logic.model.util.JsonHandler;
+
+public class StandardHighLevelStateHandlerSnippetSuppliers
+{
+       public static final CodeSnippetSupplier<HighLevelStateHandlerContext, AtomicHighLevelStateHandler> atomicHandlerSupplier;
+       public static final CodeSnippetSupplier<HighLevelStateHandlerContext, SubcomponentHighLevelStateHandler> subcomponentHandlerSupplier;
+
+       static
+       {
+               atomicHandlerSupplier = new CodeSnippetSupplier<>(null);
+               subcomponentHandlerSupplier = new CodeSnippetSupplier<>(null);
+       }
+
+       static
+       {
+               try (InputStream s = StandardHighLevelStateHandlerSnippetSuppliers.class.getResourceAsStream("./standardSnippetIDMapping.json"))
+               {
+                       if (s == null)
+                               throw new IOException("Resource not found");
+                       SnippetIDClassNames tmp = JsonHandler.readJson(s, SnippetIDClassNames.class);
+                       tmp.standardSubcomponentHandlerSuppliers.forEach(subcomponentHandlerSupplier::addStandardSnippetID);
+                       tmp.standardAtomicHandlerSuppliers.forEach(atomicHandlerSupplier::addStandardSnippetID);
+               }
+               catch (Exception e)
+               {
+                       System.err.println("Failed to initialize standard snippet ID mapping: ");
+                       e.printStackTrace();
+               }
+       }
+
+       private static class SnippetIDClassNames
+       {
+               public Map<String, String> standardSubcomponentHandlerSuppliers;
+               public Map<String, String> standardAtomicHandlerSuppliers;
+       }
+
+       private StandardHighLevelStateHandlerSnippetSuppliers()
+       {
+               throw new UnsupportedOperationException();
+       }
+}
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/atomic/AtomicHighLevelStateHandler.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/atomic/AtomicHighLevelStateHandler.java
new file mode 100644 (file)
index 0000000..dedc6d5
--- /dev/null
@@ -0,0 +1,30 @@
+package net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.atomic;
+
+import com.google.gson.JsonObject;
+
+import net.mograsim.logic.model.snippets.HighLevelStateHandler;
+
+public interface AtomicHighLevelStateHandler
+{
+       /**
+        * Gets the current value of the atomic high level state represented by this AtomicHighLevelStateHandler.<br>
+        * See {@link HighLevelStateHandler} for an explanation of high-level state IDs.
+        * 
+        * @author Daniel Kirschten
+        */
+       public Object getHighLevelState();
+
+       /**
+        * Sets the atomic high level state represented by this AtomicHighLevelStateHandler to the given value.<br>
+        * See {@link HighLevelStateHandler} for an explanation of high-level state IDs.
+        * 
+        * @author Daniel Kirschten
+        */
+       public void setHighLevelState(Object newState);
+
+       public static class AtomicHighLevelStateHandlerParams
+       {
+               public String id;
+               public JsonObject params;
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/standardSnippetIDMapping.json b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/standardSnippetIDMapping.json
new file mode 100644 (file)
index 0000000..1f3b909
--- /dev/null
@@ -0,0 +1,5 @@
+mograsim version: 0.1.3
+{
+  "standardSubcomponentHandlerSuppliers": {},
+  "standardAtomicHandlerSuppliers": {}
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/subcomponent/SubcomponentHighLevelStateHandler.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/highlevelstatehandlers/standard/subcomponent/SubcomponentHighLevelStateHandler.java
new file mode 100644 (file)
index 0000000..412bd19
--- /dev/null
@@ -0,0 +1,30 @@
+package net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.subcomponent;
+
+import com.google.gson.JsonObject;
+
+import net.mograsim.logic.model.snippets.HighLevelStateHandler;
+
+public interface SubcomponentHighLevelStateHandler
+{
+       /**
+        * Gets the current value of the given high level state of the subcomponent represented by this SubcomponentHighLevelStateHandler.<br>
+        * See {@link HighLevelStateHandler} for an explanation of high-level state IDs.
+        * 
+        * @author Daniel Kirschten
+        */
+       public Object getHighLevelState(String subStateID);
+
+       /**
+        * Sets the given high level state of the subcomponent represented by this SubcomponentHighLevelStateHandler to the given value.<br>
+        * See {@link HighLevelStateHandler} for an explanation of high-level state IDs.
+        * 
+        * @author Daniel Kirschten
+        */
+       public void setHighLevelState(String subStateID, Object newState);
+
+       public static class SubcomponentHighLevelStateHandlerParams
+       {
+               public String id;
+               public JsonObject params;
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/outlinerenderers/DefaultOutlineRenderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/outlinerenderers/DefaultOutlineRenderer.java
new file mode 100644 (file)
index 0000000..f7841dd
--- /dev/null
@@ -0,0 +1,37 @@
+package net.mograsim.logic.model.snippets.outlinerenderers;
+
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.snippets.Renderer;
+import net.mograsim.logic.model.snippets.SnippetDefinintion;
+import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
+import net.mograsim.preferences.ColorDefinition;
+import net.mograsim.preferences.ColorManager;
+import net.mograsim.preferences.Preferences;
+
+public class DefaultOutlineRenderer implements Renderer
+{
+       private final GUIComponent component;
+
+       public DefaultOutlineRenderer(SubmodelComponent component, @SuppressWarnings("unused") Void params)
+       {
+               this.component = component;
+       }
+
+       @Override
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {
+               ColorDefinition fg = Preferences.current().getColorDefinition("net.mograsim.logic.ui.color.foreground");
+               if (fg != null)
+                       gc.setForeground(ColorManager.current().toColor(fg));
+               gc.drawRectangle(component.getBounds());
+       }
+
+       static
+       {
+               SubmodelComponentSnippetSuppliers.outlineRendererSupplier.setSnippetSupplier(DefaultOutlineRenderer.class.getCanonicalName(),
+                               SnippetDefinintion.create(Void.class, DefaultOutlineRenderer::new));
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/standardSnippetIDMapping.json b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/standardSnippetIDMapping.json
new file mode 100644 (file)
index 0000000..b6a4562
--- /dev/null
@@ -0,0 +1,11 @@
+mograsim version: 0.1.3
+{
+  "standardOutlineRendererSuppliers": {},
+  "standardSymbolRendererSuppliers": {
+    "CenteredTextSymbolRenderer": "net.mograsim.logic.model.snippets.symbolrenderers.CenteredTextSymbolRenderer",
+    "SimpleRectangularLikeSymbolRenderer": "net.mograsim.logic.model.snippets.symbolrenderers.SimpleRectangularLikeSymbolRenderer"
+  },
+  "standardHighLevelStateHandlerSuppliers": {
+    "standard": "net.mograsim.logic.model.snippets.highlevelstatehandlers.standard.StandardHighLevelStateHandler"
+  }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/symbolrenderers/CenteredTextSymbolRenderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/symbolrenderers/CenteredTextSymbolRenderer.java
new file mode 100644 (file)
index 0000000..e1a6850
--- /dev/null
@@ -0,0 +1,58 @@
+package net.mograsim.logic.model.snippets.symbolrenderers;
+
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.snippets.Renderer;
+import net.mograsim.logic.model.snippets.SnippetDefinintion;
+import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
+import net.mograsim.preferences.ColorDefinition;
+import net.mograsim.preferences.ColorManager;
+import net.mograsim.preferences.Preferences;
+
+/**
+ * Renders a text (<code>"text"</code>) with a given font height (<code>"height"</code>) in the center of the component.
+ * 
+ * @author Daniel Kirschten
+ */
+public class CenteredTextSymbolRenderer implements Renderer
+{
+       private final GUIComponent component;
+       private final CenteredTextParams params;
+
+       public CenteredTextSymbolRenderer(SubmodelComponent component, CenteredTextParams params)
+       {
+               this.component = component;
+               this.params = params;
+
+       }
+
+       @Override
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {
+               Font oldFont = gc.getFont();
+               gc.setFont(new Font(oldFont.getName(), params.fontHeight, oldFont.getStyle()));
+               ColorDefinition fg = Preferences.current().getColorDefinition("net.mograsim.logic.ui.color.text");
+               if (fg != null)
+                       gc.setForeground(ColorManager.current().toColor(fg));
+               Point idSize = gc.textExtent(params.text);
+               Rectangle bounds = component.getBounds();
+               gc.drawText(params.text, bounds.x + (bounds.width - idSize.x) / 2, bounds.y + (bounds.height - idSize.y) / 2, true);
+               gc.setFont(oldFont);
+       }
+
+       public static class CenteredTextParams
+       {
+               public String text;
+               public double fontHeight;
+       }
+
+       static
+       {
+               SubmodelComponentSnippetSuppliers.symbolRendererSupplier.setSnippetSupplier(CenteredTextSymbolRenderer.class.getCanonicalName(),
+                               SnippetDefinintion.create(CenteredTextParams.class, CenteredTextSymbolRenderer::new));
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/symbolrenderers/DefaultSymbolRenderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/symbolrenderers/DefaultSymbolRenderer.java
new file mode 100644 (file)
index 0000000..3faf0b9
--- /dev/null
@@ -0,0 +1,42 @@
+package net.mograsim.logic.model.snippets.symbolrenderers;
+
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.snippets.Renderer;
+import net.mograsim.logic.model.snippets.SnippetDefinintion;
+import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
+import net.mograsim.preferences.ColorDefinition;
+import net.mograsim.preferences.ColorManager;
+import net.mograsim.preferences.Preferences;
+
+public class DefaultSymbolRenderer implements Renderer
+{
+       private static final String id = "<Symbol\nunknown>";
+
+       private final GUIComponent component;
+
+       public DefaultSymbolRenderer(SubmodelComponent component, @SuppressWarnings("unused") Void params)
+       {
+               this.component = component;
+       }
+
+       @Override
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {
+               ColorDefinition fg = Preferences.current().getColorDefinition("net.mograsim.logic.ui.color.text");
+               if (fg != null)
+                       gc.setForeground(ColorManager.current().toColor(fg));
+               Point idSize = gc.textExtent(id);
+               Rectangle bounds = component.getBounds();
+               gc.drawText(id, bounds.x + (bounds.width - idSize.x) / 2, bounds.y + (bounds.height - idSize.y) / 2, true);
+       }
+
+       static
+       {
+               SubmodelComponentSnippetSuppliers.symbolRendererSupplier.setSnippetSupplier(DefaultSymbolRenderer.class.getCanonicalName(),
+                               SnippetDefinintion.create(Void.class, DefaultSymbolRenderer::new));
+       }
+}
\ No newline at end of file
diff --git a/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/symbolrenderers/SimpleRectangularLikeSymbolRenderer.java b/net.mograsim.logic.model/src/net/mograsim/logic/model/snippets/symbolrenderers/SimpleRectangularLikeSymbolRenderer.java
new file mode 100644 (file)
index 0000000..d317385
--- /dev/null
@@ -0,0 +1,83 @@
+package net.mograsim.logic.model.snippets.symbolrenderers;
+
+import java.util.Map.Entry;
+
+import org.eclipse.swt.graphics.Color;
+
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+import net.mograsim.logic.model.model.components.GUIComponent;
+import net.mograsim.logic.model.model.components.submodels.SubmodelComponent;
+import net.mograsim.logic.model.model.wires.Pin;
+import net.mograsim.logic.model.snippets.Renderer;
+import net.mograsim.logic.model.snippets.SnippetDefinintion;
+import net.mograsim.logic.model.snippets.SubmodelComponentSnippetSuppliers;
+import net.mograsim.preferences.Preferences;
+
+/**
+ * Renders a text (<code>"centerText"</code>) with a given font height (<code>"centerTextHeight"</code>) in the center of the component and
+ * draws a label for each pin with a given font height (<code>"pinLabelHeight"</code>). The labels of pins to the left of a given x
+ * coordinate (<code>"horizontalComponentCenter"</code>) are drawn to the right of the respective pin; labels of pins to the right are drawn
+ * left. A margin (<code>"pinLabelMargin"</code>) is applied for pin label drawing.
+ * 
+ * @author Daniel Kirschten
+ */
+public class SimpleRectangularLikeSymbolRenderer implements Renderer
+{
+       private final GUIComponent component;
+       private final SimpleRectangularLikeParams params;
+
+       public SimpleRectangularLikeSymbolRenderer(SubmodelComponent component, SimpleRectangularLikeParams params)
+       {
+               this.component = component;
+               this.params = params;
+       }
+
+       @Override
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {
+               double posX = component.getPosX();
+               double posY = component.getPosY();
+               double width = component.getWidth();
+               double height = component.getHeight();
+
+               Font oldFont = gc.getFont();
+               gc.setFont(new Font(oldFont.getName(), params.centerTextHeight, oldFont.getStyle()));
+               Point textExtent = gc.textExtent(params.centerText);
+               Color textColor = Preferences.current().getColor("net.mograsim.logic.ui.color.text");
+               if (textColor != null)
+                       gc.setForeground(textColor);
+               gc.drawText(params.centerText, posX + (width - textExtent.x) / 2, posY + (height - textExtent.y) / 2, true);
+               gc.setFont(new Font(oldFont.getName(), params.pinLabelHeight, oldFont.getStyle()));
+               for (Entry<String, Pin> pinEntry : component.getPins().entrySet())
+               {
+                       String pinName = pinEntry.getKey();
+                       Pin pin = pinEntry.getValue();
+                       double pinX = pin.getRelX();
+                       double pinY = posY + pin.getRelY();
+                       textExtent = gc.textExtent(pinName);
+                       gc.drawText(pinName,
+                                       posX + pinX + (pinX > params.horizontalComponentCenter ? -textExtent.x - params.pinLabelMargin : params.pinLabelMargin),
+                                       pinY - textExtent.y / 2, true);
+               }
+               gc.setFont(oldFont);
+       }
+
+       public static class SimpleRectangularLikeParams
+       {
+               public String centerText;
+               public double centerTextHeight;
+               public double horizontalComponentCenter;
+               public double pinLabelHeight;
+               public double pinLabelMargin;
+       }
+
+       static
+       {
+               SubmodelComponentSnippetSuppliers.symbolRendererSupplier.setSnippetSupplier(
+                               SimpleRectangularLikeSymbolRenderer.class.getCanonicalName(),
+                               SnippetDefinintion.create(SimpleRectangularLikeParams.class, SimpleRectangularLikeSymbolRenderer::new));
+       }
+}
\ No newline at end of file
index 9cd9e8c..2ada2e7 100644 (file)
@@ -13,6 +13,7 @@ import com.google.gson.GsonBuilder;
 
 public class JsonHandler
 {
+       // TODO: write versions differently
        private static Gson parser = new GsonBuilder().setPrettyPrinting().create();
 
        public static <T> T readJson(String path, Class<T> type) throws IOException