Fixed & cleaned up GUIWire:
authorDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 15 Jul 2019 16:10:19 +0000 (18:10 +0200)
committerDaniel Kirschten <daniel.kirschten@gmx.de>
Mon, 15 Jul 2019 16:11:02 +0000 (18:11 +0200)
It was possible to modify a GUIWire by changing arrays or points
returned by it.

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/wires/GUIWire.java

index 91b0e3b..c5e06a5 100644 (file)
@@ -8,6 +8,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -114,8 +115,13 @@ public class HandleManager
 
        private void registerWire(GUIWire wire)
        {
-               wire.addPathChangedListener((w, diff) ->
+               Point[] path = wire.getPath();
+               AtomicInteger oldLength = new AtomicInteger(path == null ? 0 : path.length);
+               wire.addPathChangedListener(w ->
                {
+                       Point[] newPath = w.getPath();
+                       int newLength = newPath == null ? 0 : newPath.length;
+                       int diff = oldLength.getAndSet(newLength) - newLength;
                        if(diff != 0)
                        {
                                if(diff > 0)
@@ -134,9 +140,9 @@ public class HandleManager
                        pointHandlesPerWire.get(w).forEach(h -> h.updatePos());
                });
                addWireHandle(wire);
-               if (wire.getPath() == null)
+               if (path == null)
                        return;
-               for (int i = 0; i < wire.getPath().length; i++)
+               for (int i = 0; i < path.length; i++)
                {
                        addWirePointHandle(wire);
                }
index dcb9451..0e6c455 100644 (file)
@@ -10,9 +10,8 @@ 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.wires.GUIWire;
-import net.mograsim.logic.model.model.wires.GUIWire.PathChangedListener;
 
-public class WireHandle extends Handle implements PathChangedListener
+public class WireHandle extends Handle
 {
        private boolean selected = false;
        private final static double WIDTH = 2.0;
@@ -22,7 +21,7 @@ public class WireHandle extends Handle implements PathChangedListener
        public WireHandle(GUIWire parent)
        {
                this.parent = parent;
-               parent.addPathChangedListener(this);
+               parent.addPathChangedListener(c -> updateBounds());
                updateBounds();
        }
        
@@ -30,7 +29,7 @@ public class WireHandle extends Handle implements PathChangedListener
        void destroy()
        {
                super.destroy();
-               parent.removePathChangedListener(this);
+               parent.removePathChangedListener(c -> updateBounds());
        }
 
        public void updateBounds()
@@ -152,10 +151,4 @@ public class WireHandle extends Handle implements PathChangedListener
        {
                return HandleType.WIRE;
        }
-
-       @Override
-       public void pathChanged(GUIWire wire, int diff)
-       {
-               updateBounds();
-       }
 }
index d9b7cb9..7146d63 100644 (file)
@@ -2,9 +2,8 @@ package net.mograsim.logic.model.model.wires;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Set;
+import java.util.function.Consumer;
 
 import org.eclipse.swt.SWT;
 
@@ -59,8 +58,7 @@ public class GUIWire
        private double[] effectivePath;
 
        private final List<Runnable> redrawListeners;
-
-       private final Set<PathChangedListener> pathChangedListeners;
+       private final List<Consumer<GUIWire>> pathChangedListeners;
 
        /**
         * A LogicObserver calling redrawListeners. Used for logic model bindings.
@@ -150,8 +148,6 @@ public class GUIWire
         */
        public GUIWire(ViewModelModifiable model, Pin pin1, Pin pin2, Point... path)
        {
-               pathChangedListeners = new HashSet<>();
-               logicObs = (i) -> callRedrawListeners();
                this.model = model;
                this.logicWidth = pin1.logicWidth;
                if (pin2.logicWidth != pin1.logicWidth)
@@ -164,6 +160,9 @@ public class GUIWire
                this.bounds = new Rectangle(0, 0, -1, -1);
 
                redrawListeners = new ArrayList<>();
+               pathChangedListeners = new ArrayList<>();
+
+               logicObs = (i) -> callRedrawListeners();
 
                pin1.addPinMovedListener(p -> pinMoved());
                pin2.addPinMovedListener(p -> pinMoved());
@@ -288,6 +287,8 @@ public class GUIWire
                gc.drawPolyline(effectivePath);
        }
 
+       // operations concerning the path
+
        /**
         * The user-defined path between {@link #pin1} and {@link #pin2}. Note that this is not neccessarily equal to the effective path drawn
         * in {@link #render(GeneralGC)}.<br>
@@ -298,7 +299,77 @@ public class GUIWire
         */
        public Point[] getPath()
        {
-               return path == null ? null : path.clone();
+               return deepPathCopy(path);
+       }
+
+       public void setPath(Point... path)
+       {
+               this.path = deepPathCopy(path);
+               recalculateEffectivePath();
+               callPathChangedListeners();
+               callRedrawListeners();
+       }
+
+       public Point getPathPoint(int index)
+       {
+               return pointCopy(path[index]);
+       }
+
+       public void setPathPoint(Point p, int index)
+       {
+               path[index] = pointCopy(p);
+               recalculateEffectivePath();
+               callPathChangedListeners();
+               callRedrawListeners();
+       }
+
+       public void insertPathPoint(Point p, int index)
+       {
+               if (path == null)
+                       path = new Point[] { pointCopy(p) };
+               else
+               {
+                       Point[] oldPath = path;
+                       path = new Point[oldPath.length + 1];
+                       System.arraycopy(oldPath, 0, path, 0, index);
+                       if (index < oldPath.length)
+                               System.arraycopy(oldPath, index, path, index + 1, oldPath.length - index);
+                       path[index] = pointCopy(p);
+               }
+       }
+
+       public void removePathPoint(int index)
+       {
+               if (path.length == 0)
+                       path = null;
+               else
+               {
+                       Point[] oldPath = path;
+                       path = new Point[oldPath.length - 1];
+                       System.arraycopy(oldPath, 0, path, 0, index);
+                       if (index < oldPath.length - 1)
+                               System.arraycopy(oldPath, index + 1, path, index, oldPath.length - index - 1);
+               }
+       }
+
+       public double[] getEffectivePath()
+       {
+               return Arrays.copyOf(effectivePath, effectivePath.length);
+       }
+
+       private static Point[] deepPathCopy(Point[] path)
+       {
+               if (path == null)
+                       return null;
+               Point[] copy = new Point[path.length];
+               for (int i = 0; i < path.length; i++)
+                       copy[i] = pointCopy(path[i]);
+               return copy;
+       }
+
+       private static Point pointCopy(Point p)
+       {
+               return new Point(p.x, p.y);
        }
 
        // logic model binding
@@ -354,29 +425,14 @@ public class GUIWire
        // listeners
 
        // @formatter:off
-       public void addRedrawListener   (Runnable listener) {redrawListeners         .add   (listener);}
+       public void addRedrawListener        (Runnable          listener) {redrawListeners     .add    (listener);}
+       public void addPathChangedListener   (Consumer<GUIWire> listener) {pathChangedListeners.add    (listener);}
 
-       public void removeRedrawListener(Runnable listener) {redrawListeners         .remove(listener);}
+       public void removeRedrawListener     (Runnable          listener) {redrawListeners     .remove(listener);}
+       public void removePathChangedListener(Consumer<GUIWire> listener) {pathChangedListeners.remove(listener);}
 
-       private void callRedrawListeners() {redrawListeners.forEach(l -> l.run());}
-       
-       public void addPathChangedListener(PathChangedListener l) { pathChangedListeners.add(l); }
-
-       public void removePathChangedListener(PathChangedListener l) { pathChangedListeners.remove(l); }
-
-       public void callPathChangedListeners(int diff) { pathChangedListeners.forEach(l -> l.pathChanged(this, diff)); }
-       
-       @FunctionalInterface
-       public static interface PathChangedListener
-       {
-               /**
-                * Called whenever the {@link Wire}'s path changes
-                * 
-                * @param wire The wire which had its path changed
-                * @param diff The length difference between before and after the path change.
-                */
-               public void pathChanged(GUIWire wire, int diff);
-       }
+       private void callRedrawListeners     () {redrawListeners     .forEach(l -> l.run   (    ));}
+       private void callPathChangedListeners() {pathChangedListeners.forEach(l -> l.accept(this));}
        // @formatter:on
 
        @Override
@@ -384,65 +440,4 @@ public class GUIWire
        {
                return "GUIWire [" + pin1 + "---" + pin2 + ", value=" + (end == null ? "null" : end.getValues()) + "]";
        }
-
-       public void setPath(Point[] path)
-       {
-               int diff = (path == null ? 0 : path.length) - (this.path == null ? 0 : this.path.length);
-               this.path = path == null ? null : path.clone();
-               recalculateEffectivePath();
-               callPathChangedListeners(diff);
-               callRedrawListeners();
-       }
-
-       public void setPathPoint(Point p, int index)
-       {
-               path[index] = p;
-               recalculateEffectivePath();
-               callPathChangedListeners(0);
-               callRedrawListeners();
-       }
-
-       public void insertPathPoint(Point p, int index)
-       {
-               Point[] path = getPath();
-               if (path == null)
-                       setPath(new Point[] { p });
-               else
-               {
-                       Point[] newPath = new Point[path.length + 1];
-                       System.arraycopy(path, 0, newPath, 0, index);
-                       if (index < path.length)
-                               System.arraycopy(path, index, newPath, index + 1, path.length - index);
-                       newPath[index] = p;
-                       setPath(newPath);
-               }
-       }
-
-       public void removePathPoint(int index)
-       {
-               Point[] path = getPath();
-               Point[] newPath = new Point[path.length - 1];
-               System.arraycopy(path, 0, newPath, 0, index);
-               if (index < path.length - 1)
-                       System.arraycopy(path, index + 1, newPath, index, path.length - index - 1);
-               setPath(newPath);
-       }
-
-       /**
-        * @throws IndexOutOfBoundsException
-        */
-       public Point getPathPoint(int index)
-       {
-               return path[index];
-       }
-
-       public int getPathLength()
-       {
-               return path.length;
-       }
-
-       public double[] getEffectivePath()
-       {
-               return effectivePath.clone();
-       }
 }
\ No newline at end of file