Adapt Editor to new system, removed json duplication
[Mograsim.git] / net.mograsim.logic.model.editor / src / net / mograsim / logic / model / editor / Editor.java
1 package net.mograsim.logic.model.editor;
2
3 import java.io.IOException;
4 import java.util.HashMap;
5 import java.util.HashSet;
6 import java.util.Map;
7 import java.util.Optional;
8 import java.util.Set;
9
10 import com.google.gson.JsonElement;
11 import com.google.gson.JsonNull;
12 import com.google.gson.JsonParser;
13 import com.google.gson.JsonSyntaxException;
14
15 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
16 import net.mograsim.logic.model.am2900.Am2900Loader;
17 import net.mograsim.logic.model.editor.handles.ComponentHandle;
18 import net.mograsim.logic.model.editor.handles.Handle;
19 import net.mograsim.logic.model.editor.handles.HandleManager;
20 import net.mograsim.logic.model.editor.handles.PinHandle;
21 import net.mograsim.logic.model.editor.states.StateManager;
22 import net.mograsim.logic.model.editor.ui.DialogManager;
23 import net.mograsim.logic.model.editor.ui.EditorGUI;
24 import net.mograsim.logic.model.model.ViewModelModifiable;
25 import net.mograsim.logic.model.model.components.GUIComponent;
26 import net.mograsim.logic.model.model.wires.GUIWire;
27 import net.mograsim.logic.model.serializing.DeserializedSubmodelComponent;
28 import net.mograsim.logic.model.serializing.IdentifierGetter;
29 import net.mograsim.logic.model.serializing.IndirectGUIComponentCreator;
30
31 public final class Editor
32 {
33         final Selection selection = new Selection();
34         final Set<ComponentInfo> copyBuffer = new HashSet<>();
35         public final DeserializedSubmodelComponent toBeEdited;
36         public final HandleManager handleManager;
37         final static Map<GUIComponent, String> identifierPerComponent = new HashMap<>();
38         public final EditorGUI gui;
39         public final StateManager stateManager;
40         private final SaveLoadManager saveManager;
41         private Snapping snapping = Snapping.ABSOLUTE;
42         private double snapX = 5, snapY = 5;
43         public final DialogManager dialogManager;
44         public final EditorUserInput userInput;
45
46         public Editor(DeserializedSubmodelComponent toBeEdited)
47         {
48                 this.toBeEdited = toBeEdited;
49                 handleManager = new HandleManager(this);
50                 gui = new EditorGUI(this);
51                 userInput = new EditorUserInput(this);
52                 stateManager = new StateManager(this);
53                 handleManager.init();
54                 saveManager = new SaveLoadManager(this);
55                 dialogManager = new DialogManager(gui.shell);
56
57                 toBeEdited.submodel.addComponentRemovedListener(c -> identifierPerComponent.remove(c));
58
59                 gui.open();
60         }
61
62         public ViewModelModifiable getSubmodel()
63         {
64                 return toBeEdited.getSubmodelModifiable();
65         }
66
67         public Selection getSelection()
68         {
69                 return selection;
70         }
71
72         // TODO: Remove this error prone method: Relative offset may change between multiple moves,
73         // because Handles have different ways of responding to reqMove(...), causing strange behaviour
74         @Deprecated
75         public void moveSelection(double x, double y)
76         {
77                 Point ref = selection.getTopLeft();
78                 Point snapped = new Point(x, y);
79                 applySnapping(snapped);
80
81                 for (Handle c : selection)
82                 {
83                         double newX, newY;
84                         newX = snapped.x + c.getPosX() - ref.x;
85                         newY = snapped.y + c.getPosY() - ref.y;
86                         c.reqMove(newX, newY);
87                 }
88         }
89
90         public void moveHandles(double x, double y, Map<Handle, Point> handleOffsetMap)
91         {
92                 Point snapped = new Point(x, y);
93                 applySnapping(snapped);
94
95                 for (Handle c : handleOffsetMap.keySet())
96                 {
97                         Point offset = handleOffsetMap.get(c);
98                         double newX, newY;
99                         newX = snapped.x + offset.x;
100                         newY = snapped.y + offset.y;
101                         c.reqMove(newX, newY);
102                 }
103         }
104
105         public void deleteSelection()
106         {
107                 selection.forEach(h -> h.reqDelete());
108                 selection.clear();
109         }
110
111         public void copy()
112         {
113                 copyBuffer.clear();
114                 Point refPoint = selection.getTopLeft();
115                 for (Handle h : selection)
116                 {
117                         Optional<ComponentInfo> cInfo = h.reqCopy(refPoint);
118                         if (cInfo.isPresent())
119                                 copyBuffer.add(cInfo.get());
120                 }
121         }
122
123         public void paste(double x, double y)
124         {
125                 selection.clear();
126                 for (ComponentInfo info : copyBuffer)
127                 {
128                         GUIComponent comp = addComponent(info.identifier, info.params);
129                         ComponentHandle h = handleManager.getHandle(comp);
130                         h.reqMove(info.relX, info.relY);
131                         selection.add(h);
132                 }
133                 moveSelection(x, y);
134         }
135
136         public void save()
137         {
138                 saveManager.save();
139         }
140
141         public void saveAs()
142         {
143                 saveManager.openSaveAsDialog();
144         }
145
146         public void addComponent(double x, double y)
147         {
148                 boolean successful = false;
149                 JsonElement params = JsonNull.INSTANCE;
150                 outer: while (!successful)
151                 {
152                         String selected = gui.getAddListSelected();
153                         try
154                         {
155                                 GUIComponent c = addComponent(selected, params);
156                                 selection.clear();
157                                 selection.add(handleManager.getHandle(c));
158                                 moveSelection(x, y);
159                                 successful = true;
160                         }
161                         catch (@SuppressWarnings("unused") UnsupportedOperationException | JsonSyntaxException | NumberFormatException e)
162                         {
163                                 String result = DialogManager.openMultiLineTextDialog("Add component", "Create", "Cancel", "Parameters:");
164                                 if (result == null)
165                                         break outer;
166                                 params = new JsonParser().parse(result);
167                         }
168                 }
169         }
170
171         private GUIComponent addComponent(String identifier, JsonElement params)
172         {
173                 GUIComponent comp = IndirectGUIComponentCreator.createComponent(toBeEdited.getSubmodelModifiable(), identifier, params);
174                 identifierPerComponent.put(comp, identifier);
175                 return comp;
176         }
177
178         public static String getIdentifier(GUIComponent c)
179         {
180                 if (identifierPerComponent.containsKey(c))
181                         return identifierPerComponent.get(c);
182                 return new IdentifierGetter().componentIDs.apply(c);
183         }
184
185         public void duplicate()
186         {
187                 copy();
188                 Point origin = selection.getTopLeft();
189                 paste(origin.x + 20, origin.y + 20);
190         }
191
192         private void applySnapping(Point newP)
193         {
194                 switch (snapping)
195                 {
196                 case OFF:
197                         break;
198                 case ABSOLUTE:
199                         newP.x = (int) (newP.x / snapX + .5) * snapX;
200                         newP.y = (int) (newP.y / snapY + .5) * snapY;
201                         break;
202                 default:
203                         break;
204                 }
205         }
206
207         public static class ComponentInfo
208         {
209                 public final double relX, relY;
210                 public final String identifier;
211                 public final JsonElement params;
212
213                 public ComponentInfo(double relX, double relY, String identifier, JsonElement params)
214                 {
215                         this.relX = relX;
216                         this.relY = relY;
217                         this.identifier = identifier;
218                         this.params = params;
219                 }
220         }
221
222         @SuppressWarnings("unused")
223         public void addWire(PinHandle a, PinHandle b)
224         {
225                 new GUIWire(toBeEdited.getSubmodelModifiable(), a.getPin(), b.getPin(), new Point[0]);
226         }
227
228         public static enum Snapping
229         {
230                 OFF, ABSOLUTE;
231
232                 @Override
233                 public String toString()
234                 {
235                         return super.toString().toLowerCase();
236                 }
237         }
238
239         public static void main(String[] args) throws IOException
240         {
241                 Am2900Loader.setup();
242                 SaveLoadManager.openLoadDialog();
243         }
244
245         public Snapping getSnapping()
246         {
247                 return snapping;
248         }
249
250         public void setSnapping(Snapping snapping)
251         {
252                 this.snapping = snapping;
253         }
254 }