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