Fixed ViewModels being modifiable via GUIComponent/Wire#destroy.
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 2 Sep 2019 11:09:41 +0000 (13:09 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 2 Sep 2019 11:10:05 +0000 (13:10 +0200)
net.mograsim.logic.model.am2900/src/net/mograsim/logic/model/examples/ReserializeJSONsSettingUsages.java
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/handles/ComponentHandle.java
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/handles/HandleManager.java
net.mograsim.logic.model.editor/src/net/mograsim/logic/model/editor/handles/WireHandle.java
net.mograsim.logic.model/src/net/mograsim/logic/model/model/ViewModel.java
net.mograsim.logic.model/src/net/mograsim/logic/model/model/ViewModelModifiable.java
net.mograsim.logic.model/src/net/mograsim/logic/model/model/components/GUIComponent.java
net.mograsim.logic.model/src/net/mograsim/logic/model/model/wires/GUIWire.java

index d5faf7e..2f41153 100644 (file)
@@ -75,7 +75,7 @@ public class ReserializeJSONsSettingUsages
        {
                Set<GUIWire> wiresConnectedToPin = comp.submodel.getWiresByName().values().stream()
                                .filter(w -> w.getPin1() == interfacePin || w.getPin2() == interfacePin).collect(Collectors.toSet());
-               wiresConnectedToPin.forEach(GUIWire::destroy);
+               wiresConnectedToPin.forEach(comp.getSubmodelModifiable()::destroyWire);
                comp.removeSubmodelInterface(interfacePin.name);
                comp.addSubmodelInterface(
                                new MovablePin(comp, interfacePin.name, interfacePin.logicWidth, usage, interfacePin.getRelX(), interfacePin.getRelY()));
index b44f1cf..fedca49 100644 (file)
@@ -10,19 +10,22 @@ import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 import net.mograsim.logic.model.editor.Editor;
 import net.mograsim.logic.model.editor.Editor.ComponentInfo;
+import net.mograsim.logic.model.model.ViewModelModifiable;
 import net.mograsim.logic.model.model.components.GUIComponent;
 import net.mograsim.logic.model.serializing.IdentifierGetter;
 
 public class ComponentHandle extends Handle
 {
+       private final ViewModelModifiable model;
        public final GUIComponent parent;
        private final static double POS_OFFSET = 2.0d;
        private final static double LENGTH_OFFSET = POS_OFFSET * 2;
        boolean selected = false;
 
-       public ComponentHandle(GUIComponent parent)
+       public ComponentHandle(ViewModelModifiable model, GUIComponent parent)
        {
                super(4);
+               this.model = model;
                this.parent = parent;
                Rectangle bounds = parent.getBounds();
                setSize(bounds.width, bounds.height);
@@ -80,7 +83,7 @@ public class ComponentHandle extends Handle
        @Override
        public void reqDelete()
        {
-               parent.destroy();
+               model.destroyComponent(parent);
        }
 
        @Override
index 24eb36d..5189003 100644 (file)
@@ -154,7 +154,7 @@ public class HandleManager
 
        private void addComponentHandle(GUIComponent c)
        {
-               ComponentHandle h = new ComponentHandle(c);
+               ComponentHandle h = new ComponentHandle(editor.getSubmodel(), c);
                handlePerComp.put(c, h);
                addHandle(h);
        }
@@ -240,7 +240,7 @@ public class HandleManager
 
        private void addWireHandle(GUIWire w)
        {
-               WireHandle h = new WireHandle(w);
+               WireHandle h = new WireHandle(editor.getSubmodel(), w);
                handlePerWire.put(w, h);
                addHandle(h);
        }
index 7629dcb..be9a5ca 100644 (file)
@@ -9,6 +9,7 @@ import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 import net.mograsim.logic.model.editor.states.EditorState;
+import net.mograsim.logic.model.model.ViewModelModifiable;
 import net.mograsim.logic.model.model.wires.GUIWire;
 
 public class WireHandle extends Handle
@@ -16,11 +17,13 @@ public class WireHandle extends Handle
        private boolean selected = false;
        private final static double WIDTH = 2.0;
        private final static double WIDTH_SQUARED = WIDTH * WIDTH;
+       private final ViewModelModifiable model;
        public final GUIWire parent;
 
-       public WireHandle(GUIWire parent)
+       public WireHandle(ViewModelModifiable model, GUIWire parent)
        {
                super(5);
+               this.model = model;
                this.parent = parent;
                parent.addPathChangedListener(c -> updateBounds());
                updateBounds();
@@ -68,7 +71,7 @@ public class WireHandle extends Handle
        @Override
        public void reqDelete()
        {
-               parent.destroy();
+               model.destroyWire(parent);
        }
 
        @Override
index c85f1fd..cf679cd 100644 (file)
@@ -13,8 +13,10 @@ import net.mograsim.logic.model.model.wires.GUIWire;
 public class ViewModel
 {
        private final Map<String, GUIComponent> components;
+       private final Map<String, Runnable> componentDestroyFunctions;
        private final Map<String, GUIComponent> componentsUnmodifiable;
        private final Map<String, GUIWire> wires;
+       private final Map<String, Runnable> wireDestroyFunctions;
        private final Map<String, GUIWire> wiresUnmodifiable;
 
        private final List<Consumer<? super GUIComponent>> componentAddedListeners;
@@ -28,8 +30,10 @@ public class ViewModel
        protected ViewModel()
        {
                components = new HashMap<>();
+               componentDestroyFunctions = new HashMap<>();
                componentsUnmodifiable = Collections.unmodifiableMap(components);
                wires = new HashMap<>();
+               wireDestroyFunctions = new HashMap<>();
                wiresUnmodifiable = Collections.unmodifiableMap(wires);
 
                componentAddedListeners = new ArrayList<>();
@@ -42,22 +46,27 @@ public class ViewModel
        /**
         * Adds the given component to the list of components and calls all componentAddedListeners. Don't call this method from application
         * code as it is automatically called in {@link GUIComponent}'s constructor.
+        * 
+        * @author Daniel Kirschten
         */
-       protected void componentCreated(GUIComponent component)
+       protected void componentCreated(GUIComponent component, Runnable destroyed)
        {
                if (components.containsKey(component.name))
                        throw new IllegalStateException("Don't add the same component twice!");
                components.put(component.name, component);
+               componentDestroyFunctions.put(component.name, destroyed);
                callComponentAddedListeners(component);
                requestRedraw();
        }
 
        /**
-        * Removes the given component from the list of components and calls all componentRemovedListeners. Don't call this method from
-        * application code as it is automatically called in {@link GUIComponent#destroy()}.
+        * Destroyes the given component, removes it from the list of components and calls all componentRemovedListeners.
+        * 
+        * @author Daniel Kirschten
         */
-       protected void componentDestroyed(GUIComponent component)
+       protected void destroyComponent(GUIComponent component)
        {
+               componentDestroyFunctions.get(component.name).run();
                if (!components.containsKey(component.name))
                        throw new IllegalStateException("Don't remove the same component twice!");
                components.remove(component.name);
@@ -66,24 +75,28 @@ public class ViewModel
        }
 
        /**
-        * Adds the given wire to the list of wires and calls all wireAddedListeners. Don't call this method from application code as it is
-        * automatically called in {@link GUIWire}'s constructor(s).
+        * Adds the given wire to the list of wires and calls all wireAddedListeners.
+        * 
+        * @author Daniel Kirschten
         */
-       protected void wireCreated(GUIWire wire)
+       protected void wireCreated(GUIWire wire, Runnable destroyed)
        {
                if (wires.containsKey(wire.name))
                        throw new IllegalStateException("Don't add the same wire twice!");
                wires.put(wire.name, wire);
+               wireDestroyFunctions.put(wire.name, destroyed);
                callWireAddedListeners(wire);
                requestRedraw();
        }
 
        /**
-        * Removes the given wire from the list of wires and calls all wireRemovedListeners. Don't call this method from application code as it
-        * is automatically called in {@link GUIWire#destroy()}.
+        * Destroys the given wire, removes it from the list of wires and calls all wireRemovedListeners.
+        * 
+        * @author Daniel Kirschten
         */
-       protected void wireDestroyed(GUIWire wire)
+       protected void destroyWire(GUIWire wire)
        {
+               wireDestroyFunctions.get(wire.name).run();
                if (!wires.containsKey(wire.name))
                        throw new IllegalStateException("Don't remove the same wire twice!");
                wires.remove(wire.name);
index 97993a7..b4fa4f5 100644 (file)
@@ -5,7 +5,6 @@ import java.util.Set;
 import net.mograsim.logic.model.model.components.GUIComponent;
 import net.mograsim.logic.model.model.wires.GUIWire;
 
-//TODO a ViewModel is modifiable without casting to ViewModelModifiable via GUIWire::destroy and GUIComponent::destroy
 public class ViewModelModifiable extends ViewModel
 {
        public String getDefaultComponentName(GUIComponent component)
@@ -41,26 +40,26 @@ public class ViewModelModifiable extends ViewModel
        }
 
        @Override
-       public void componentCreated(GUIComponent component)
+       public void componentCreated(GUIComponent component, Runnable destroyed)
        {
-               super.componentCreated(component);
+               super.componentCreated(component, destroyed);
        }
 
        @Override
-       public void componentDestroyed(GUIComponent component)
+       public void destroyComponent(GUIComponent component)
        {
-               super.componentDestroyed(component);
+               super.destroyComponent(component);
        }
 
        @Override
-       public void wireCreated(GUIWire wire)
+       public void wireCreated(GUIWire wire, Runnable destroyed)
        {
-               super.wireCreated(wire);
+               super.wireCreated(wire, destroyed);
        }
 
        @Override
-       public void wireDestroyed(GUIWire wire)
+       public void destroyWire(GUIWire wire)
        {
-               super.wireDestroyed(wire);
+               super.destroyWire(wire);
        }
 }
\ No newline at end of file
index 60e8fb2..11c4334 100644 (file)
@@ -70,19 +70,19 @@ public abstract class GUIComponent implements JSONSerializable
 
                // TODO this will crash the high level state debug shell because submodel is not yet set.
                // The same problem exists in ViewModelModifiable.getDefaultComponentName; see there
-               model.componentCreated(this);
+               model.componentCreated(this, this::destroyed);
        }
 
        /**
-        * Destroys this component. This method implicitly calls {@link ViewModelModifiable#componentDestroyed(GUIComponent)
-        * componentDestroyed()} for the model this component is a part of.
+        * Destroys this component. This method is called from {@link ViewModelModifiable#componentDestroyed(GUIComponent) destroyComponent()}
+        * of the model this component is a part of.<br>
+        * When overriding, make sure to also call the original implementation.
         * 
         * @author Daniel Kirschten
         */
-       public void destroy()
+       protected void destroyed()
        {
                pinsByName.values().forEach(p -> pinRemovedListeners.forEach(l -> l.accept(p)));
-               model.componentDestroyed(this);
        }
 
        // pins
index 99241a3..8b91fc4 100644 (file)
@@ -252,18 +252,18 @@ public class GUIWire
 
                recalculateEffectivePath();
 
-               model.wireCreated(this);
+               model.wireCreated(this, this::destroyed);
        }
 
        /**
-        * Destroys this wire. This method implicitly calls {@link ViewModelModifiable#wireDestroyed(GUIWire) wireDestroyed()} for the model
-        * this component is a part of.
+        * Destroys this wire. This method is called from {@link ViewModelModifiable#wireDestroyed(GUIWire) wireDestroyed()} of the model this
+        * wire is a part of.
         * 
         * @author Daniel Kirschten
         */
-       public void destroy()
+       private void destroyed()
        {
-               model.wireDestroyed(this);
+               // nothing to do
        }
 
        // pins