02b022a9e70a96714d54e51a0d06fb9659285693
[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
15 /**
16  * Creates {@link SubmodelComponent}s from {@link SubmodelComponentParams}
17  */
18 public final class GUICustomComponentCreator
19 {
20         private static final String rectC = SimpleRectangularSubmodelComponent.class.getSimpleName();
21
22         /**
23          * Creates a {@link SubmodelComponent} from the {@link SubmodelComponentParams}, specified at the given path. The returned
24          * SubmodelComponent can also be e.g. a {@link SimpleRectangularSubmodelComponent}, depending on what the
25          * {@link SubmodelComponentParams} describe.
26          * 
27          * @param path The path of the file describing the {@link SubmodelComponentParams}, which define the new {@link SubmodelComponent}
28          * @return A new SubmodelComponent, as described in the file located at the given path
29          */
30         public static SubmodelComponent create(ViewModelModifiable model, String path)
31         {
32                 try
33                 {
34                         SubmodelComponentParams params = SubmodelComponentParams.readJson(path);
35                         SubmodelComponent ret = create(model, params, path);
36                         return ret;
37                 }
38                 catch (IOException e)
39                 {
40                         System.err.println("Failed to construct GUICustomComponent. Parameters were not found.");
41                         e.printStackTrace();
42                 }
43                 return new SimpleRectangularSubmodelComponent(model, 0, "ERROR");
44         }
45
46         /**
47          * Creates a {@link SubmodelComponent} from the specified {@link SubmodelComponentParams}. The returned SubmodelComponent can also be
48          * e.g. a {@link SimpleRectangularSubmodelComponent}, depending on what the {@link SubmodelComponentParams} describe.
49          * 
50          * @param params The parameters describing the {@link SubmodelComponent}
51          * @param path   This value is used when the new {@link SubmodelComponent} is an inner component to a different SubmodelComponent, which
52          *               is being saved to a file; Then, the new {@link SubmodelComponent} is referenced by its given path within the file.
53          * @return A new SubmodelComponent, as described by the {@link SubmodelComponentParams}
54          */
55         public static SubmodelComponent create(ViewModelModifiable model, SubmodelComponentParams params, String path)
56         {
57                 SubmodelComponent comp = null;
58                 if (rectC.equals(params.type))
59                 {
60                         comp = createRectComponent(model, params);
61                 }
62
63                 if (comp == null)
64                 {
65                         comp = createSubmodelComponent(model, params);
66                 }
67                 comp.identifierDelegate = () -> "file:".concat(path);
68                 initInnerComponents(comp, params.composition);
69                 return comp;
70         }
71
72         // May return null
73         private static SimpleRectangularSubmodelComponent createRectComponent(ViewModelModifiable model, SubmodelComponentParams params)
74         {
75                 try
76                 {
77                         Map<String, Object> m = params.specialized;
78                         SimpleRectangularSubmodelComponent rect = new SimpleRectangularSubmodelComponent(model,
79                                         ((Number) m.get(SimpleRectangularSubmodelComponent.kLogicWidth)).intValue(),
80                                         (String) m.get(SimpleRectangularSubmodelComponent.kLabel));
81                         rect.setSubmodelScale(params.composition.innerScale);
82                         // rect.setSize(params.width, params.height);
83
84                         // TODO save & restore names
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.logicWidth);
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, int logicWidth)
161                         throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
162                         NoSuchMethodException, SecurityException, ClassNotFoundException
163         {
164                 Class<?> c = Class.forName(classname);
165                 Object comp;
166                 try
167                 {
168                         Constructor<?> constructor = c.getConstructor(ViewModelModifiable.class);
169                         comp = constructor.newInstance(parent.submodelModifiable);
170                 }
171                 catch (@SuppressWarnings("unused") NoSuchMethodException e)
172                 {
173                         Constructor<?> constructor = c.getConstructor(ViewModelModifiable.class, int.class);
174                         comp = constructor.newInstance(parent.submodelModifiable, logicWidth);
175                 }
176
177                 if (comp instanceof GUIComponent)
178                         return (GUIComponent) comp;
179                 throw new IllegalArgumentException("Class given as subcomponent was not a GUIComponent!");
180         }
181 }