General SubmodelComponents can now be saved to a json format
[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
7 import net.mograsim.logic.ui.model.ViewModelModifiable;
8 import net.mograsim.logic.ui.model.components.params.GeneralComponentParams;
9 import net.mograsim.logic.ui.model.components.params.RectComponentParams;
10 import net.mograsim.logic.ui.model.components.params.SubComponentParams;
11 import net.mograsim.logic.ui.model.components.params.RectComponentParams.InnerComponentParams;
12 import net.mograsim.logic.ui.model.components.params.RectComponentParams.InnerWireParams;
13 import net.mograsim.logic.ui.model.components.params.SubComponentParams.InterfacePinParams;
14 import net.mograsim.logic.ui.model.wires.GUIWire;
15
16 public class GUICustomComponentCreator
17 {
18         private static class CustomRectComponent extends SimpleRectangularSubmodelComponent
19         {
20                 private String path;
21
22                 protected CustomRectComponent(ViewModelModifiable model, int logicWidth, String label, String path)
23                 {
24                         super(model, logicWidth, label);
25                         this.path = path;
26                 }
27
28                 @Override
29                 public String getIdentifier()
30                 {
31                         return "file:".concat(path);
32                 }
33         }
34
35         public static SubmodelComponent create(ViewModelModifiable model, String path)
36         {
37                 try
38                 {
39                         if (path.endsWith(RectComponentParams.fileExtension))
40                         {
41                                 RectComponentParams params = RectComponentParams.readJson(path);
42                                 SubmodelComponent ret = create(model, params, path);
43                                 return ret;
44                         } else if (path.endsWith(SubComponentParams.fileExtension))
45                         {
46                                 SubComponentParams params = SubComponentParams.readJson(path);
47                                 SubmodelComponent ret = create(model, params, path);
48                                 return ret;
49                         } else
50                                 throw new IOException(String.format("\"%s\" does not have a valid file extension. Must be either %s or %s", path,
51                                                 RectComponentParams.fileExtension, SubComponentParams.fileExtension));
52                 }
53                 catch (IOException e)
54                 {
55                         System.err.println("Failed to construct GUICustomComponent. Parameters were not found.");
56                         e.printStackTrace();
57                 }
58                 return new CustomRectComponent(model, 0, "ERROR", "NONE");
59         }
60
61         /**
62          * @param path This value is used when the new SubmodelComponent is an inner component to a different SubmodelComponent, which is being
63          *             saved to a file; Then, the new SubmodelComponent is referenced by its given path within the file.
64          */
65         public static SimpleRectangularSubmodelComponent create(ViewModelModifiable model, RectComponentParams params, String path)
66         {
67                 CustomRectComponent comp = new CustomRectComponent(model, params.logicWidth, params.displayName, path);
68                 comp.setSubmodelScale(params.composition.innerScale);
69                 comp.setInputCount(params.inputCount);
70                 comp.setOutputCount(params.outputCount);
71                 initSubmodelComponents(comp, params.composition);
72                 return comp;
73         }
74
75         /**
76          * @param path This value is used when the new SubmodelComponent is an inner component to a different SubmodelComponent, which is being
77          *             saved to a file; Then, the new SubmodelComponent is referenced by its given path within the file.
78          */
79         public static SubmodelComponent create(ViewModelModifiable model, SubComponentParams params, String path)
80         {
81                 // As SubmodelComponent is abstract, for now SubmodelComponents are instantiated as SimpleRectangularSubmodelComponents
82                 CustomRectComponent comp = new CustomRectComponent(model, 0, "", path);
83                 comp.setSubmodelScale(params.composition.innerScale);
84                 comp.setSize(params.width, params.height);
85                 for (InterfacePinParams iPinParams : params.interfacePins)
86                 {
87                         comp.addSubmodelInterface(iPinParams.logicWidth, iPinParams.location.x, iPinParams.location.y);
88                 }
89                 initSubmodelComponents(comp, params.composition);
90                 return comp;
91         }
92
93         @SuppressWarnings("unused")
94         private static void initSubmodelComponents(SubmodelComponent comp, GeneralComponentParams params)
95         {
96                 try
97                 {
98                         GUIComponent[] components = new GUIComponent[params.subComps.length];
99                         for (int i = 0; i < components.length; i++)
100                         {
101                                 InnerComponentParams cParams = params.subComps[i];
102                                 String path = cParams.type;
103                                 if (path.startsWith("class:"))
104                                 {
105                                         path = path.substring(6);
106                                         components[i] = createInnerComponentFromClass(comp, path, cParams.logicWidth);
107                                         components[i].moveTo(cParams.pos.x, cParams.pos.y);
108                                 } else if (path.startsWith("file:"))
109                                 {
110                                         path = path.substring(5);
111                                         components[i] = create(comp.submodelModifiable, path);
112                                         components[i].moveTo(cParams.pos.x, cParams.pos.y);
113                                 } else
114                                         throw new IllegalArgumentException("Invalid submodel type! Type was neither prefixed by 'class:' nor by 'file:'");
115                         }
116
117                         for (int i = 0; i < params.innerWires.length; i++)
118                         {
119                                 InnerWireParams innerWire = params.innerWires[i];
120                                 new GUIWire(comp.submodelModifiable,
121                                                 comp.submodelModifiable.getComponents().get(innerWire.pin1.compId).getPins().get(innerWire.pin1.pinIndex),
122                                                 comp.submodelModifiable.getComponents().get(innerWire.pin2.compId).getPins().get(innerWire.pin2.pinIndex),
123                                                 innerWire.path);
124                         }
125                 }
126                 catch (Exception e)
127                 {
128                         System.err.println("Failed to create custom component!");
129                         e.printStackTrace();
130                 }
131         }
132
133         private static GUIComponent createInnerComponentFromClass(SubmodelComponent parent, String classname, int logicWidth)
134                         throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException,
135                         NoSuchMethodException, SecurityException, ClassNotFoundException
136         {
137                 Class<?> c = Class.forName(classname);
138                 Object comp;
139                 try
140                 {
141                         Constructor<?> constructor = c.getConstructor(ViewModelModifiable.class);
142                         comp = constructor.newInstance(parent.submodelModifiable);
143                 }
144                 catch (@SuppressWarnings("unused") NoSuchMethodException e)
145                 {
146                         Constructor<?> constructor = c.getConstructor(ViewModelModifiable.class, int.class);
147                         comp = constructor.newInstance(parent.submodelModifiable, logicWidth);
148                 }
149
150                 if (comp instanceof GUIComponent)
151                         return (GUIComponent) comp;
152                 throw new IllegalArgumentException("Class given as subcomponent was not a GUIComponent!");
153         }
154 }