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 / handles / HandleManager.java
1 package net.mograsim.logic.model.editor.handles;
2
3 import java.util.ArrayList;
4 import java.util.Collection;
5 import java.util.Collections;
6 import java.util.HashMap;
7 import java.util.HashSet;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.concurrent.atomic.AtomicInteger;
12 import java.util.function.Consumer;
13 import java.util.stream.Collectors;
14
15 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
16 import net.mograsim.logic.model.editor.Editor;
17 import net.mograsim.logic.model.editor.states.EditorState;
18 import net.mograsim.logic.model.model.ViewModelModifiable;
19 import net.mograsim.logic.model.model.components.GUIComponent;
20 import net.mograsim.logic.model.model.wires.GUIWire;
21 import net.mograsim.logic.model.model.wires.MovablePin;
22 import net.mograsim.logic.model.model.wires.Pin;
23
24 public class HandleManager
25 {
26         private final Map<Pin, StaticPinHandle> handlePerPin;
27         private final Map<Pin, InterfacePinHandle> handlePerInterfacePin;
28         private final Map<GUIWire, List<WirePointHandle>> pointHandlesPerWire;
29         private final Map<GUIWire, WireHandle> handlePerWire;
30         private final Set<Handle> handles;
31         private final Set<WirePointHandle> wirePointHandles;
32         private final Map<GUIComponent, ComponentHandle> handlePerComp;
33
34         private final Collection<Consumer<Handle>> handleAddedListeners;
35         private final Collection<Consumer<Handle>> handleRemovedListeners;
36         private final Editor editor;
37         private boolean initialized = false;
38
39         private CornerHandle cornerHandle;
40
41         public HandleManager(Editor editor)
42         {
43                 this.editor = editor;
44                 handlePerPin = new HashMap<>();
45                 handlePerInterfacePin = new HashMap<>();
46                 pointHandlesPerWire = new HashMap<>();
47                 handlePerComp = new HashMap<>();
48                 handles = new HashSet<>();
49                 wirePointHandles = new HashSet<>();
50                 handlePerWire = new HashMap<>();
51
52                 handleAddedListeners = new ArrayList<>();
53                 handleRemovedListeners = new ArrayList<>();
54
55                 ViewModelModifiable model = editor.getSubmodel();
56
57                 model.addComponentAddedListener(c -> registerComponent(c));
58
59                 model.addComponentRemovedListener(c ->
60                 {
61                         removeComponentHandle(c);
62                 });
63
64                 model.addWireAddedListener(w ->
65                 {
66                         registerWire(w);
67                 });
68
69                 model.addWireRemovedListener(w ->
70                 {
71                         removeWireHandle(w);
72                         removeWirePointHandles(w);
73                 });
74         }
75
76         ////////////////////////////////////////
77         // -- Setting up initial handles -- ///
78         //////////////////////////////////////
79
80         public void init()
81         {
82                 if (initialized)
83                         System.err.println("Warning! HandleManager was already initialized.");
84                 else
85                 {
86                         ViewModelModifiable model = editor.getSubmodel();
87                         Map<String, GUIComponent> compsByName = model.getComponentsByName();
88                         Set<GUIComponent> comps = new HashSet<>(compsByName.values());
89                         GUIComponent interfaceComp = compsByName.get("_submodelinterface");
90                         comps.remove(interfaceComp);
91                         registerInterfaceComponent(interfaceComp);
92                         comps.forEach(c -> registerComponent(c));
93
94                         model.getWiresByName().values().forEach(w -> registerWire(w));
95                         addHandle(cornerHandle = new CornerHandle(editor.toBeEdited));
96                 }
97         }
98
99         private void registerInterfaceComponent(GUIComponent c)
100         {
101                 c.getPins().values().forEach(p -> addInterfacePinHandle(p));
102                 c.addPinAddedListener(p -> addInterfacePinHandle(p));
103                 c.addPinRemovedListener(p -> removeInterfacePinHandle(p));
104         }
105
106         private void registerComponent(GUIComponent c)
107         {
108                 addComponentHandle(c);
109
110                 c.getPins().values().forEach(p -> addPinHandle(p));
111
112                 c.addPinAddedListener(p -> addPinHandle(p));
113                 c.addPinRemovedListener(p -> removePinHandle(p));
114         }
115
116         private void registerWire(GUIWire wire)
117         {
118                 Point[] path = wire.getPath();
119                 AtomicInteger oldLength = new AtomicInteger(path == null ? 0 : path.length);
120                 wire.addPathChangedListener(w ->
121                 {
122                         Point[] newPath = w.getPath();
123                         int newLength = newPath == null ? 0 : newPath.length;
124                         int diff = newLength - oldLength.getAndSet(newLength);
125                         if (diff != 0)
126                         {
127                                 if (diff > 0)
128                                 {
129                                         for (int i = 0; i < diff; i++)
130                                                 addWirePointHandle(w);
131                                 }
132
133                                 List<WirePointHandle> wpHandles = pointHandlesPerWire.get(w);
134                                 int size = wpHandles.size();
135                                 for (int i = 0; i < size; i++)
136                                 {
137                                         wpHandles.get(i).setIndex(i);
138                                 }
139                         }
140                         pointHandlesPerWire.get(w).forEach(h -> h.updatePos());
141                 });
142                 addWireHandle(wire);
143                 if (path == null)
144                         return;
145                 for (int i = 0; i < path.length; i++)
146                 {
147                         addWirePointHandle(wire);
148                 }
149         }
150
151         /////////////////////////////////////
152         // -- Adding/Removing handles -- ///
153         ///////////////////////////////////
154
155         private void addComponentHandle(GUIComponent c)
156         {
157                 ComponentHandle h = new ComponentHandle(c);
158                 handlePerComp.put(c, h);
159                 addHandle(h);
160         }
161
162         private void removeComponentHandle(GUIComponent c)
163         {
164                 ComponentHandle h = handlePerComp.get(c);
165                 handlePerComp.remove(c);
166                 removeHandle(h);
167         }
168
169         private void addPinHandle(Pin owner)
170         {
171                 StaticPinHandle h = new StaticPinHandle(owner);
172                 handlePerPin.put(owner, h);
173                 addHandle(h);
174         }
175
176         private void removePinHandle(Pin owner)
177         {
178                 StaticPinHandle h = handlePerPin.get(owner);
179                 handlePerPin.remove(owner);
180                 removeHandle(h);
181         }
182
183         private void addInterfacePinHandle(Pin p)
184         {
185                 // The following is not an alternative to the cast, because the new pin is not yet in the map, when the listener is called
186                 // editor.toBeEdited.getSubmodelMovablePins().get(p.name);
187                 MovablePin pM = (MovablePin) p;
188                 InterfacePinHandle h = new InterfacePinHandle(pM, editor.toBeEdited);
189                 handlePerInterfacePin.put(pM, h);
190                 addHandle(h);
191         }
192
193         private void removeInterfacePinHandle(Pin p)
194         {
195                 InterfacePinHandle h = handlePerInterfacePin.get(p);
196                 handlePerInterfacePin.remove(p);
197                 removeHandle(h);
198         }
199
200         private void addWirePointHandle(GUIWire w)
201         {
202                 List<WirePointHandle> wireHandles = pointHandlesPerWire.get(w);
203                 WirePointHandle h;
204                 if (wireHandles != null)
205                         wireHandles.add(h = new WirePointHandle(this, w, wireHandles.size()));
206                 else
207                 {
208                         wireHandles = new ArrayList<>();
209                         h = new WirePointHandle(this, w, 0);
210                         wireHandles.add(h);
211                         pointHandlesPerWire.put(h.parent, wireHandles);
212                 }
213                 this.wirePointHandles.add(h);
214                 addHandle(h);
215         }
216
217         void destroyWirePointHandle(GUIWire owner, WirePointHandle h)
218         {
219                 if (pointHandlesPerWire.containsKey(owner))
220                 {
221                         List<WirePointHandle> handles = pointHandlesPerWire.get(owner);
222                         int pointIndex = handles.indexOf(h);
223                         handles.remove(pointIndex);
224                         removeHandle(h);
225                         owner.removePathPoint(pointIndex);
226                 }
227         }
228
229         private void removeWirePointHandles(GUIWire owner)
230         {
231                 if (!pointHandlesPerWire.containsKey(owner))
232                         return;
233                 pointHandlesPerWire.get(owner).forEach(h ->
234                 {
235                         wirePointHandles.remove(h);
236                         removeHandle(h);
237                 });
238                 pointHandlesPerWire.remove(owner);
239         }
240
241         private void addWireHandle(GUIWire w)
242         {
243                 WireHandle h = new WireHandle(w);
244                 handlePerWire.put(w, h);
245                 addHandle(h);
246         }
247
248         private void removeWireHandle(GUIWire w)
249         {
250                 WireHandle h = handlePerWire.get(w);
251                 handlePerWire.remove(w);
252                 removeHandle(h);
253         }
254
255         private void addHandle(Handle h)
256         {
257                 handles.add(h);
258                 callHandleAddedListeners(h);
259         }
260
261         private void removeHandle(Handle h)
262         {
263                 handles.remove(h);
264                 callHandleRemovedListeners(h);
265                 h.destroy();
266         }
267
268         public StaticPinHandle getHandle(Pin parent)
269         {
270                 return handlePerPin.get(parent);
271         }
272
273         public ComponentHandle getHandle(GUIComponent parent)
274         {
275                 return handlePerComp.get(parent);
276         }
277
278         public WireHandle getHandle(GUIWire parent)
279         {
280                 return handlePerWire.get(parent);
281         }
282
283         public Handle getInterfacePinHandle(Pin p)
284         {
285                 return handlePerInterfacePin.get(p);
286         }
287
288         /**
289          * @return A Collection of the registered {@link WirePointHandle}s of the specified wire
290          */
291         public Collection<WirePointHandle> getWirePointHandles(GUIWire parent)
292         {
293                 return pointHandlesPerWire.get(parent).stream().collect(Collectors.toSet());
294         }
295
296         /**
297          * @return An unmodifiable view of all registered {@link Handle}s
298          */
299         public Collection<Handle> getHandles()
300         {
301                 return Collections.unmodifiableCollection(handles);
302         }
303
304         /**
305          * @return An unmodifiable view of all registered {@link StaticPinHandle}s
306          */
307         public Collection<StaticPinHandle> getPinHandles()
308         {
309                 return Collections.unmodifiableCollection(handlePerPin.values());
310         }
311
312         /**
313          * @return An unmodifiable view of all registered {@link InterfacePinHandle}s
314          */
315         public Collection<InterfacePinHandle> getInterfacePinHandles()
316         {
317                 return Collections.unmodifiableCollection(handlePerInterfacePin.values());
318         }
319
320         /**
321          * @return An unmodifiable view of all registered {@link ComponentHandle}s
322          */
323         public Collection<ComponentHandle> getComponentHandles()
324         {
325                 return Collections.unmodifiableCollection(handlePerComp.values());
326         }
327
328         /**
329          * @return An unmodifiable view of all registered {@link WireHandle}s
330          */
331         public Collection<WireHandle> getWireHandles()
332         {
333                 return Collections.unmodifiableCollection(handlePerWire.values());
334         }
335
336         /**
337          * @return An unmodifiable view of all registered {@link WirePointHandle}s
338          */
339         public Collection<WirePointHandle> getWirePointHandles()
340         {
341                 return Collections.unmodifiableSet(wirePointHandles);
342         }
343
344         public void click(Point clicked, int stateMask)
345         {
346                 EditorState entryState = editor.stateManager.getState();
347
348                 if (!cornerHandle.click(clicked.x, clicked.y, stateMask, entryState))
349                         if (!click(handlePerPin.values(), clicked, entryState, stateMask))
350                                 if (!click(handlePerInterfacePin.values(), clicked, entryState, stateMask))
351                                         if (!click(getWirePointHandles(), clicked, entryState, stateMask))
352                                                 if (!click(getWireHandles(), clicked, entryState, stateMask))
353                                                         if (!click(handlePerComp.values(), clicked, entryState, stateMask))
354                                                                 entryState.clickedEmpty(clicked, stateMask);
355                 entryState.clicked(clicked, stateMask);
356         }
357
358         private static boolean click(Collection<? extends Handle> handles, Point clicked, EditorState state, int stateMask)
359         {
360                 for (Handle h : handles)
361                         if (h.click(clicked.x, clicked.y, stateMask, state))
362                                 return true;
363                 return false;
364         }
365
366         public void addHandleAddedListener(Consumer<Handle> c)
367         {
368                 handleAddedListeners.add(c);
369         }
370
371         private void callHandleAddedListeners(Handle added)
372         {
373                 handleAddedListeners.forEach(l -> l.accept(added));
374         }
375
376         public void removeHandleAddedListener(Consumer<Handle> c)
377         {
378                 handleAddedListeners.remove(c);
379         }
380
381         public void addHandleRemovedListener(Consumer<Handle> c)
382         {
383                 handleRemovedListeners.add(c);
384         }
385
386         private void callHandleRemovedListeners(Handle removed)
387         {
388                 handleRemovedListeners.forEach(l -> l.accept(removed));
389         }
390
391         public void removeHandleRemovedListener(Consumer<Handle> c)
392         {
393                 handleRemovedListeners.remove(c);
394         }
395 }