Implemented SubmodelComponent.clicked(); removed obsolete TODOs
[Mograsim.git] / net.mograsim.logic.ui / src / net / mograsim / logic / ui / model / components / GUICustomComponentCreator.java
1 package net.mograsim.logic.ui.model.components;
2
3 import java.io.IOException;
4 import java.lang.reflect.Constructor;
5 import java.lang.reflect.InvocationTargetException;
6 import java.util.Map;
7
8 import net.mograsim.logic.ui.model.ViewModelModifiable;
9 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.ComponentCompositionParams.InnerComponentParams;
10 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.ComponentCompositionParams;
11 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.InnerWireParams;
12 import net.mograsim.logic.ui.model.components.SubmodelComponentParams.InterfacePinParams;
13 import net.mograsim.logic.ui.model.wires.GUIWire;
14 import net.mograsim.logic.ui.model.wires.WireCrossPoint;
15
16 /**
17  * Creates {@link SubmodelComponent}s from {@link SubmodelComponentParams}
18  */
19 public final class GUICustomComponentCreator
20 {
21         private static final String rectC = SimpleRectangularSubmodelComponent.class.getSimpleName();
22
23         /**
24          * Creates a {@link SubmodelComponent} from the {@link SubmodelComponentParams}, specified at the given path. The returned
25          * SubmodelComponent can also be e.g. a {@link SimpleRectangularSubmodelComponent}, depending on what the
26          * {@link SubmodelComponentParams} describe.
27          * 
28          * @param path The path of the file describing the {@link SubmodelComponentParams}, which define the new {@link SubmodelComponent}
29          * @return A new SubmodelComponent, as described in the file located at the given path
30          */
31         public static SubmodelComponent create(ViewModelModifiable model, String path)
32         {
33                 try
34                 {
35                         SubmodelComponentParams params = SubmodelComponentParams.readJson(path);
36                         SubmodelComponent ret = create(model, params, path);
37                         return ret;
38                 }
39                 catch (IOException e)
40                 {
41                         System.err.println("Failed to construct GUICustomComponent. Parameters were not found.");
42                         e.printStackTrace();
43                 }
44                 return new SimpleRectangularSubmodelComponent(model, 0, "ERROR");
45         }
46
47         /**
48          * Creates a {@link SubmodelComponent} from the specified {@link SubmodelComponentParams}. The returned SubmodelComponent can also be
49          * e.g. a {@link SimpleRectangularSubmodelComponent}, depending on what the {@link SubmodelComponentParams} describe.
50          * 
51          * @param params The parameters describing the {@link SubmodelComponent}
52          * @param path   This value is used when the new {@link SubmodelComponent} is an inner component to a different SubmodelComponent, which
53          *               is being saved to a file; Then, the new {@link SubmodelComponent} is referenced by its given path within the file.
54          * @return A new SubmodelComponent, as described by the {@link SubmodelComponentParams}
55          */
56         public static SubmodelComponent create(ViewModelModifiable model, SubmodelComponentParams params, String path)
57         {
58                 SubmodelComponent comp = null;
59                 if (rectC.equals(params.type))
60                 {
61                         comp = createRectComponent(model, params);
62                 }
63
64                 if (comp == null)
65                 {
66                         comp = createSubmodelComponent(model, params);
67                 }
68                 comp.identifierDelegate = () -> "file:".concat(path);
69                 initInnerComponents(comp, params.composition);
70                 return comp;
71         }
72
73         // May return null
74         private static SimpleRectangularSubmodelComponent createRectComponent(ViewModelModifiable model, SubmodelComponentParams params)
75         {
76                 try
77                 {
78                         Map<String, Object> m = params.specialized;
79                         SimpleRectangularSubmodelComponent rect = new SimpleRectangularSubmodelComponent(model,
80                                         ((Number) m.get(SimpleRectangularSubmodelComponent.kLogicWidth)).intValue(),
81                                         (String) m.get(SimpleRectangularSubmodelComponent.kLabel));
82                         rect.setSubmodelScale(params.composition.innerScale);
83                         // rect.setSize(params.width, params.height);
84
85                         int inputCount = ((Number) m.get(SimpleRectangularSubmodelComponent.kInCount)).intValue();
86                         String[] inputNames = new String[inputCount];
87                         for (int i = 0; i < inputCount; i++)
88                                 inputNames[i] = params.interfacePins[i].name;
89                         rect.setInputPins(inputNames);
90
91                         int outputCount = ((Number) m.get(SimpleRectangularSubmodelComponent.kOutCount)).intValue();
92                         String[] outputPins = new String[outputCount];
93                         for (int i = 0; i < outputCount; i++)
94                                 outputPins[i] = params.interfacePins[inputCount + i].name;
95                         rect.setOutputPins(outputPins);
96
97                         return rect;
98                 }
99                 catch (ClassCastException | NullPointerException e)
100                 {
101                         System.err.println("Failed to specialize component!");
102                         e.printStackTrace();
103                         return null;
104                 }
105         }
106
107         private static SubmodelComponent createSubmodelComponent(ViewModelModifiable model, SubmodelComponentParams params)
108         {
109                 // As SubmodelComponent is abstract, for now SubmodelComponents are instantiated as SimpleRectangularSubmodelComponents
110                 SubmodelComponent comp = new SimpleRectangularSubmodelComponent(model, 0, "");
111                 comp.setSubmodelScale(params.composition.innerScale);
112                 comp.setSize(params.width, params.height);
113                 for (InterfacePinParams iPinParams : params.interfacePins)
114                 {
115                         comp.addSubmodelInterface(iPinParams.name, iPinParams.logicWidth, iPinParams.location.x, iPinParams.location.y);
116                 }
117                 return comp;
118         }
119
120         @SuppressWarnings("unused")
121         private static void initInnerComponents(SubmodelComponent comp, ComponentCompositionParams params)
122         {
123                 try
124                 {
125                         GUIComponent[] components = new GUIComponent[params.subComps.length];
126                         for (int i = 0; i < components.length; i++)
127                         {
128                                 InnerComponentParams cParams = params.subComps[i];
129                                 String path = cParams.type;
130                                 if (path.startsWith("class:"))
131                                 {
132                                         path = path.substring(6);
133                                         components[i] = createInnerComponentFromClass(comp, path, cParams.params);
134                                         components[i].moveTo(cParams.pos.x, cParams.pos.y);
135                                 } else if (path.startsWith("file:"))
136                                 {
137                                         path = path.substring(5);
138                                         components[i] = create(comp.submodelModifiable, path);
139                                         components[i].moveTo(cParams.pos.x, cParams.pos.y);
140                                 } else
141                                         throw new IllegalArgumentException("Invalid submodel type! Type was neither prefixed by 'class:' nor by 'file:'");
142                         }
143
144                         for (int i = 0; i < params.innerWires.length; i++)
145                         {
146                                 InnerWireParams innerWire = params.innerWires[i];
147                                 new GUIWire(comp.submodelModifiable,
148                                                 comp.submodelModifiable.getComponents().get(innerWire.pin1.compId).getPin(innerWire.pin1.pinName),
149                                                 comp.submodelModifiable.getComponents().get(innerWire.pin2.compId).getPin(innerWire.pin2.pinName), innerWire.path);
150                         }
151                 }
152                 catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | SecurityException
153                                 | ClassNotFoundException | IllegalArgumentException e)
154                 {
155                         System.err.println("Failed to initialize custom component!");
156                         e.printStackTrace();
157                 }
158         }
159
160         private static GUIComponent createInnerComponentFromClass(SubmodelComponent parent, String classname, Map<String, Object> params)
161                         throws InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SecurityException,
162                         ClassNotFoundException
163         {
164                 Class<?> c = Class.forName(classname);
165                 Object comp;
166                 if (SimpleRectangularGUIGate.class.isAssignableFrom(c) || WireCrossPoint.class.equals(c))
167                 {
168                         Constructor<?> constructor = c.getConstructor(ViewModelModifiable.class, int.class);
169                         comp = constructor.newInstance(parent.submodelModifiable,
170                                         ((Number) params.get(SimpleRectangularGUIGate.kLogicWidth)).intValue());
171                 } else
172                 {
173                         Constructor<?> constructor = c.getConstructor(ViewModelModifiable.class);
174                         comp = constructor.newInstance(parent.submodelModifiable);
175                 }
176                 return (GUIComponent) comp;
177         }
178 }