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