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
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");
package net.mograsim.logic.model.examples;
import java.io.IOException;
+import java.io.UncheckedIOException;
import com.google.gson.JsonNull;
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;
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);
+ }
}
}
{
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())
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);
}
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
{
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);
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);
package net.mograsim.logic.model.examples;
+import java.io.IOException;
+import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.List;
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
{
@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
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,
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
*/
/**
* 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)
/**
* 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)
// serializing
@SuppressWarnings("static-method") // this method is intended to be overridden
- public JsonElement getParams()
+ public JsonElement getParamsForSerializing()
{
return JsonNull.INSTANCE;
}
* {@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);
}
// serializing
@Override
- public JsonElement getParams()
+ public JsonElement getParamsForSerializing()
{
return new JsonPrimitive(text);
}
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;
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)
{
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}.
*/
*/
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.
*/
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;
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
/**
*
* @author Daniel Kirschten
*/
- protected double getSubmodelScale()
+ public double getSubmodelScale()
{
return submodelScale;
}
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
// serializing
@Override
- public JsonElement getParams()
+ public JsonElement getParamsForSerializing()
{
return new JsonPrimitive(pin.logicWidth);
}
+++ /dev/null
-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
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
this.symbolRenderer = symbolRenderer;
}
+ public void setHighLevelStateHandler(HighLevelStateHandler highLevelStateHandler)
+ {
+ this.highLevelStateHandler = highLevelStateHandler;
+ }
+
public ViewModelModifiable getSubmodelModifiable()
{
return submodelModifiable;
}
@Override
- protected Pin addSubmodelInterface(MovablePin supermodelPin)
+ public Pin addSubmodelInterface(MovablePin supermodelPin)
{
return super.addSubmodelInterface(supermodelPin);
}
+
+ // TODO static initializer
}
\ No newline at end of file
import java.io.IOException;
import java.io.InputStream;
+import java.io.UncheckedIOException;
import java.util.HashMap;
import java.util.Map;
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
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);
}
+++ /dev/null
-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);
- }
- }
-}
public String symbolRendererSnippetID;
public JsonElement symbolRendererParams;
+ public String highLevelStateHandlerSnippetID;
+ public JsonElement highLevelStateHandlerParams;
+
public static class InterfacePinParams
{
public Point location;
--- /dev/null
+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
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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
+++ /dev/null
-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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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();
+ }
+}
--- /dev/null
+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
--- /dev/null
+mograsim version: 0.1.3
+{
+ "standardSubcomponentHandlerSuppliers": {},
+ "standardAtomicHandlerSuppliers": {}
+}
\ No newline at end of file
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
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