Merge branch 'development' of
authorFabian Stemmler <stemmler@in.tum.de>
Wed, 29 May 2019 16:07:52 +0000 (18:07 +0200)
committerFabian Stemmler <stemmler@in.tum.de>
Wed, 29 May 2019 16:07:52 +0000 (18:07 +0200)
https://gitlab.lrz.de/lrr-tum/students/eragp-misim-2019 into development

# Conflicts:
# LogicUI/src/era/mi/gui/LogicUIStandalone.java

18 files changed:
LogicUI/src/era/mi/gui/LogicUICanvas.java
LogicUI/src/era/mi/gui/LogicUIStandalone.java
LogicUI/src/era/mi/gui/examples/Playground.java
LogicUI/src/era/mi/gui/model/components/GUIAndGate.java
LogicUI/src/era/mi/gui/model/components/GUIComponent.java
LogicUI/src/era/mi/gui/model/components/GUIManualSwitch.java
LogicUI/src/era/mi/gui/model/components/GUINotGate.java
LogicUI/src/era/mi/gui/model/components/GUIOrGate.java
LogicUI/src/era/mi/gui/model/components/RectangularShapedGUIGate.java [deleted file]
LogicUI/src/era/mi/gui/model/components/SimpleRectangularGUIGate.java [new file with mode: 0644]
LogicUI/src/era/mi/gui/model/wires/GUIWire.java
LogicUI/src/era/mi/gui/model/wires/MovablePin.java
LogicUI/src/era/mi/gui/model/wires/Pin.java
LogicUI/src/era/mi/gui/model/wires/WireCrossPoint.java
LogicUI/src/era/mi/gui/modeladapter/LogicModelParameters.java [new file with mode: 0644]
LogicUI/src/era/mi/gui/modeladapter/ViewLogicModelAdapter.java
LogicUI/src/era/mi/gui/modeladapter/componentadapters/ComponentAdapter.java [new file with mode: 0644]
LogicUI/src/era/mi/gui/modeladapter/componentadapters/SimpleGateAdapter.java [new file with mode: 0644]

index 2115e7b..7faefe3 100644 (file)
@@ -8,6 +8,7 @@ import org.eclipse.swt.widgets.Event;
 
 import era.mi.gui.model.ViewModel;
 import era.mi.gui.model.components.GUIComponent;
+import era.mi.gui.model.wires.GUIWire;
 import era.mi.gui.model.wires.Pin;
 import net.haspamelodica.swt.helper.gcs.GeneralGC;
 import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
@@ -40,30 +41,34 @@ public class LogicUICanvas extends ZoomableCanvas
                        p.removePinMovedListener(redrawConsumer);
                        redrawThreadsafe();
                };
-               model.addComponentAddedListener(c ->
+               Consumer<? super GUIComponent> componentAddedListener = c ->
                {
-                       c.addComponentChangedListener(redrawConsumer);
+                       c.addComponentLookChangedListener(redrawConsumer);
                        c.addComponentMovedListener(redrawConsumer);
                        c.addPinAddedListener(pinAddedListener);
                        c.addPinRemovedListener(pinRemovedListener);
                        redrawThreadsafe();
-               });
+               };
+               model.addComponentAddedListener(componentAddedListener);
+               model.getComponents().forEach(componentAddedListener);
                model.addComponentRemovedListener(c ->
                {
-                       c.removeComponentChangedListener(redrawConsumer);
+                       c.removeComponentLookChangedListener(redrawConsumer);
                        c.removeComponentMovedListener(redrawConsumer);
                        c.removePinAddedListener(pinAddedListener);
                        c.removePinRemovedListener(pinRemovedListener);
                        redrawThreadsafe();
                });
-               model.addWireAddedListener(w ->
+               Consumer<? super GUIWire> wireAddedListener = w ->
                {
-                       w.addWireChangedListener(redrawConsumer);
+                       w.addWireLookChangedListener(redrawConsumer);
                        redrawThreadsafe();
-               });
+               };
+               model.addWireAddedListener(wireAddedListener);
+               model.getWires().forEach(wireAddedListener);
                model.addWireRemovedListener(w ->
                {
-                       w.removeWireChangedListener(redrawConsumer);
+                       w.removeWireLookChangedListener(redrawConsumer);
                        redrawThreadsafe();
                });
 
index a471166..3312308 100644 (file)
@@ -8,6 +8,9 @@ import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Shell;
 
 import era.mi.gui.model.ViewModel;
+import era.mi.gui.modeladapter.LogicModelParameters;
+import era.mi.gui.modeladapter.ViewLogicModelAdapter;
+import era.mi.logic.timeline.Timeline;
 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasOverlay;
 import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInput;
 
@@ -19,6 +22,7 @@ import net.haspamelodica.swt.helper.zoomablecanvas.helper.ZoomableCanvasUserInpu
 public class LogicUIStandalone
 {
        private ViewModel model;
+       private Timeline timeline;
 
        private final Display display;
        private final Shell shell;
@@ -37,6 +41,12 @@ public class LogicUIStandalone
                userInput.buttonZoom = 2;
                userInput.enableUserInput();
                new ZoomableCanvasOverlay(ui, null).enableScale();
+
+               // TODO don't do this here
+               LogicModelParameters params = new LogicModelParameters();
+               params.gateProcessTime = 50;
+               params.wireTravelTime = 10;
+               timeline = ViewLogicModelAdapter.convert(model, params);
        }
 
        public LogicUICanvas getLogicUICanvas()
@@ -50,34 +60,33 @@ public class LogicUIStandalone
        public void run()
        {
                AtomicBoolean running = new AtomicBoolean(true);
-//             Thread simulationThread = new Thread(() ->
-//             {
-//                     while (running.get())
-//                     {
-//                             // always execute to keep timeline from "hanging behind" for too long
-//                             timeline.executeUntil(timeline.laterThan(System.currentTimeMillis()), System.currentTimeMillis() + 10);         
-//                             model.timeline.executeUpTo(System.currentTimeMillis(), System.currentTimeMillis() + 10);
-//                             long sleepTime;
-//                             if (model.timeline.hasNext())
-//                                     sleepTime = model.timeline.nextEventTime() - System.currentTimeMillis();
-//                             else
-//                                     sleepTime = 10;
-//                             try
-//                             {
-//                                     if (sleepTime > 0)
-//                                             Thread.sleep(sleepTime);
-//                             }
-//                             catch (InterruptedException e)
-//                             {
-//                             } // it is normal execution flow to be interrupted
-//                     }
-//             });
-//             simulationThread.start();
-//             model.timeline.addEventAddedListener(event ->
-//             {
-//                     if (event.getTiming() <= System.currentTimeMillis())
-//                             simulationThread.interrupt();
-//             });
+               Thread simulationThread = new Thread(() ->
+               {
+                       while (running.get())
+                       {
+                               // always execute to keep timeline from "hanging behind" for too long
+                               timeline.executeUntil(timeline.laterThan(System.currentTimeMillis()), System.currentTimeMillis() + 10);
+                               long sleepTime;
+                               if (timeline.hasNext())
+                                       sleepTime = timeline.nextEventTime() - System.currentTimeMillis();
+                               else
+                                       sleepTime = 10;
+                               try
+                               {
+                                       if (sleepTime > 0)
+                                               Thread.sleep(sleepTime);
+                               }
+                               catch (InterruptedException e)
+                               {
+                               } // it is normal execution flow to be interrupted
+                       }
+               });
+               simulationThread.start();
+               timeline.addEventAddedListener(event ->
+               {
+                       if (event.getTiming() <= System.currentTimeMillis())
+                               simulationThread.interrupt();
+               });
 
                shell.open();
                while (!shell.isDisposed())
index 78524b7..cf9f1e0 100644 (file)
@@ -11,23 +11,27 @@ import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
 
 public class Playground
 {
-       private static final int WIRE_DELAY = 10;
-       private static final int OR_DELAY = 50;
-       private static final int NOT_DELAY = 50;
-
        public static void main(String[] args)
        {
                ViewModel model = new ViewModel();
+               GUIAndGate andGate = new GUIAndGate(model, 1);
+               andGate.moveTo(10, 10);
+               GUINotGate notGate = new GUINotGate(model, 1);
+               notGate.moveTo(10, 40);
+
+               new GUIWire(model, andGate.getPins().get(0), notGate.getPins().get(1), new Point(20, 50));
+
                LogicUIStandalone ui = new LogicUIStandalone(model);
-               addComponentsAndWires(ui, model);
+
+               ui.getLogicUICanvas().addListener(SWT.KeyDown, e -> notGate.moveTo(150, 10));
                ui.run();
        }
 
        public static void addComponentsAndWires(LogicUIStandalone ui, ViewModel model)
        {
-               GUIAndGate andGate = new GUIAndGate(model);
+               GUIAndGate andGate = new GUIAndGate(model, 1);
                andGate.moveTo(10, 10);
-               GUINotGate notGate = new GUINotGate(model);
+               GUINotGate notGate = new GUINotGate(model, 1);
                notGate.moveTo(10, 40);
 
                new GUIWire(model, andGate.getPins().get(0), notGate.getPins().get(1), new Point(20, 50));
index 4f69d36..65f1db4 100644 (file)
@@ -2,11 +2,11 @@ package era.mi.gui.model.components;
 
 import era.mi.gui.model.ViewModel;
 
-public class GUIAndGate extends RectangularShapedGUIGate
+public class GUIAndGate extends SimpleRectangularGUIGate
 {
-       public GUIAndGate(ViewModel model)
+       public GUIAndGate(ViewModel model, int logicWidth)
        {
-               super(model, "&", false);
-               setInputCount(2);
+               super(model, logicWidth, "&", false);
+               setInputCount(2);// TODO make variable
        }
 }
\ No newline at end of file
index dc06461..ccb24a2 100644 (file)
@@ -17,7 +17,7 @@ public abstract class GUIComponent
        private final List<Pin> pins;
        protected final List<Pin> pinsUnmodifiable;
 
-       private final List<Consumer<? super GUIComponent>> componentChangedListeners;
+       private final List<Consumer<? super GUIComponent>> componentLookChangedListeners;
        private final List<Consumer<? super GUIComponent>> componentMovedListeners;
        private final List<Consumer<? super Pin>> pinAddedListeners;
        private final List<Consumer<? super Pin>> pinRemovedListeners;
@@ -29,7 +29,7 @@ public abstract class GUIComponent
                this.pins = new ArrayList<>();
                this.pinsUnmodifiable = Collections.unmodifiableList(pins);
 
-               this.componentChangedListeners = new ArrayList<>();
+               this.componentLookChangedListeners = new ArrayList<>();
                this.componentMovedListeners = new ArrayList<>();
                this.pinAddedListeners = new ArrayList<>();
                this.pinRemovedListeners = new ArrayList<>();
@@ -76,20 +76,20 @@ public abstract class GUIComponent
        }
 
        // @formatter:off
-       public void addComponentChangedListener   (Consumer<? super GUIComponent> listener) {componentChangedListeners.add   (listener);}
-       public void addComponentMovedListener     (Consumer<? super GUIComponent> listener) {componentMovedListeners  .add   (listener);}
-       public void addPinAddedListener           (Consumer<? super Pin         > listener) {pinAddedListeners        .add   (listener);}
-       public void addPinRemovedListener         (Consumer<? super Pin         > listener) {pinRemovedListeners      .add   (listener);}
-
-       public void removeComponentChangedListener(Consumer<? super GUIComponent> listener) {componentChangedListeners.remove(listener);}
-       public void removeComponentMovedListener  (Consumer<? super GUIComponent> listener) {componentMovedListeners  .remove(listener);}
-       public void removePinAddedListener        (Consumer<? super Pin         > listener) {pinAddedListeners        .remove(listener);}
-       public void removePinRemovedListener      (Consumer<? super Pin         > listener) {pinRemovedListeners      .remove(listener);}
-
-       protected void callComponentChangedListeners(     ) {componentChangedListeners.forEach(l -> l.accept(this));}
-       private   void callComponentMovedListeners  (     ) {componentMovedListeners  .forEach(l -> l.accept(this));}
-       private   void callPinAddedListeners        (Pin p) {pinAddedListeners        .forEach(l -> l.accept(p   ));}
-       private   void callPinRemovedListeners      (Pin p) {pinRemovedListeners      .forEach(l -> l.accept(p   ));}
+       public void addComponentLookChangedListener   (Consumer<? super GUIComponent> listener) {componentLookChangedListeners.add   (listener);}
+       public void addComponentMovedListener         (Consumer<? super GUIComponent> listener) {componentMovedListeners      .add   (listener);}
+       public void addPinAddedListener               (Consumer<? super Pin         > listener) {pinAddedListeners            .add   (listener);}
+       public void addPinRemovedListener             (Consumer<? super Pin         > listener) {pinRemovedListeners          .add   (listener);}
+                                                  
+       public void removeComponentLookChangedListener(Consumer<? super GUIComponent> listener) {componentLookChangedListeners.remove(listener);}
+       public void removeComponentMovedListener      (Consumer<? super GUIComponent> listener) {componentMovedListeners      .remove(listener);}
+       public void removePinAddedListener            (Consumer<? super Pin         > listener) {pinAddedListeners            .remove(listener);}
+       public void removePinRemovedListener          (Consumer<? super Pin         > listener) {pinRemovedListeners          .remove(listener);}
+
+       protected void callComponentLookChangedListeners(     ) {componentLookChangedListeners.forEach(l -> l.accept(this));}
+       private   void callComponentMovedListeners      (     ) {componentMovedListeners      .forEach(l -> l.accept(this));}
+       private   void callPinAddedListeners            (Pin p) {pinAddedListeners            .forEach(l -> l.accept(p   ));}
+       private   void callPinRemovedListeners          (Pin p) {pinRemovedListeners          .forEach(l -> l.accept(p   ));}
        // @form  atter:on
 
        /**
@@ -101,7 +101,7 @@ public abstract class GUIComponent
        {
                bounds.width = width;
                bounds.height = height;
-               callComponentChangedListeners();
+               callComponentLookChangedListeners();
        }
 
        protected void addPin(Pin pin)
index 870a55a..6008329 100644 (file)
@@ -23,7 +23,7 @@ public class GUIManualSwitch extends GUIComponent
        {
                super(model);
                setSize(width, height);
-               addPin(new Pin(this, width, height / 2));
+               addPin(new Pin(this, 1, width, height / 2));
        }
 
        @Override
@@ -44,7 +44,7 @@ public class GUIManualSwitch extends GUIComponent
                this.logicSwitch = logicSwitch;
                this.end = end;
                // TODO when ManualSwitch supports it, add listeners
-               end.addObserver((i, o) -> callComponentChangedListeners());
+               end.addObserver((i, o) -> callComponentLookChangedListeners());
        }
 
        @Override
index 5f41592..c22d9b2 100644 (file)
@@ -2,11 +2,11 @@ package era.mi.gui.model.components;
 
 import era.mi.gui.model.ViewModel;
 
-public class GUINotGate extends RectangularShapedGUIGate
+public class GUINotGate extends SimpleRectangularGUIGate
 {
-       public GUINotGate(ViewModel model)
+       public GUINotGate(ViewModel model, int logicWidth)
        {
-               super(model, "1", true);
+               super(model, logicWidth, "1", true);
                setInputCount(1);
        }
 }
\ No newline at end of file
index df64bba..a732509 100644 (file)
@@ -2,11 +2,11 @@ package era.mi.gui.model.components;
 
 import era.mi.gui.model.ViewModel;
 
-public class GUIOrGate extends RectangularShapedGUIGate
+public class GUIOrGate extends SimpleRectangularGUIGate
 {
-       public GUIOrGate(ViewModel model)
+       public GUIOrGate(ViewModel model, int logicWidth)
        {
-               super(model, "\u22651", false);// ">=1"
+               super(model, logicWidth, "\u22651", false);// ">=1"
                setInputCount(2);
        }
 }
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/model/components/RectangularShapedGUIGate.java b/LogicUI/src/era/mi/gui/model/components/RectangularShapedGUIGate.java
deleted file mode 100644 (file)
index c7d0b34..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-package era.mi.gui.model.components;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import era.mi.gui.model.ViewModel;
-import era.mi.gui.model.wires.MovablePin;
-import era.mi.gui.model.wires.Pin;
-import net.haspamelodica.swt.helper.gcs.GeneralGC;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
-import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
-
-public class RectangularShapedGUIGate extends GUIComponent
-{
-       private static final double width = 20;
-       private static final double pinDistance = 10;
-       private static final double fontHeight = 5;
-       private static final double invertedCircleDiam = 3.5;
-
-       private final String label;
-       private final boolean isInverted;
-       private final double rectWidth;
-
-       private MovablePin outputPin;
-       private final List<Pin> inputPins;
-
-       protected RectangularShapedGUIGate(ViewModel model, String label, boolean isInverted)
-       {
-               super(model);
-               this.label = label;
-               this.isInverted = isInverted;
-               this.rectWidth = width - (isInverted ? invertedCircleDiam : 0);
-               this.outputPin = new MovablePin(this, width, 0);
-               addPin(outputPin);
-               this.inputPins = new ArrayList<>();
-               setInputCount(1);
-       }
-
-       protected void setInputCount(int inputCount)
-       {
-               int oldInputCount = inputPins.size();
-               setSize(width, inputCount * pinDistance);
-               if (oldInputCount > inputCount)
-                       while (inputPins.size() > inputCount)
-                               removePin(inputPins.get(inputCount));
-               else if (oldInputCount < inputCount)
-                       for (int i = oldInputCount; i < inputCount; i++)
-                       {
-                               Pin pin = new Pin(this, 0, pinDistance / 2 + i * pinDistance);
-                               inputPins.add(pin);
-                               addPin(pin);
-                       }
-               outputPin.setRelPos(width, inputCount * pinDistance / 2);
-       }
-
-       @Override
-       public void render(GeneralGC gc, Rectangle visibleRegion)
-       {
-               double posX = getBounds().x;
-               double posY = getBounds().y;
-
-               double height = inputPins.size() * pinDistance;
-               gc.drawRectangle(posX, posY, rectWidth, height);
-               Font oldFont = gc.getFont();
-               Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
-               gc.setFont(labelFont);
-               Point textExtent = gc.textExtent(label);
-               gc.drawText(label, posX + (rectWidth - textExtent.x) / 2, posY + (height - textExtent.y) / 2, true);
-               gc.setFont(oldFont);
-               if (isInverted)
-                       gc.drawOval(posX + rectWidth, posY + (height - invertedCircleDiam) / 2, invertedCircleDiam, invertedCircleDiam);
-       }
-}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/model/components/SimpleRectangularGUIGate.java b/LogicUI/src/era/mi/gui/model/components/SimpleRectangularGUIGate.java
new file mode 100644 (file)
index 0000000..eb396cc
--- /dev/null
@@ -0,0 +1,89 @@
+package era.mi.gui.model.components;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import era.mi.gui.model.ViewModel;
+import era.mi.gui.model.wires.MovablePin;
+import era.mi.gui.model.wires.Pin;
+import net.haspamelodica.swt.helper.gcs.GeneralGC;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Font;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
+import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
+
+public class SimpleRectangularGUIGate extends GUIComponent
+{
+       private static final double width = 20;
+       private static final double pinDistance = 10;
+       private static final double fontHeight = 5;
+       private static final double invertedCircleDiam = 3.5;
+
+       private final String label;
+       protected final int logicWidth;
+       private final boolean isInverted;
+       private final double rectWidth;
+
+       private MovablePin outputPin;
+       private final List<Pin> inputPins;
+       private final List<Pin> inputPinsUnmodifiable;
+
+       protected SimpleRectangularGUIGate(ViewModel model, int logicWidth, String label, boolean isInverted)
+       {
+               super(model);
+               this.label = label;
+               this.logicWidth = logicWidth;
+               this.isInverted = isInverted;
+               this.rectWidth = width - (isInverted ? invertedCircleDiam : 0);
+               this.outputPin = new MovablePin(this, logicWidth, width, 0);
+               addPin(outputPin);
+               this.inputPins = new ArrayList<>();
+               this.inputPinsUnmodifiable = Collections.unmodifiableList(inputPins);
+               setInputCount(1);
+       }
+
+       protected void setInputCount(int inputCount)
+       {
+               int oldInputCount = inputPins.size();
+               setSize(width, inputCount * pinDistance);
+               if (oldInputCount > inputCount)
+                       while (inputPins.size() > inputCount)
+                               removePin(inputPins.get(inputCount));
+               else if (oldInputCount < inputCount)
+                       for (int i = oldInputCount; i < inputCount; i++)
+                       {
+                               Pin pin = new Pin(this, logicWidth, 0, pinDistance / 2 + i * pinDistance);
+                               inputPins.add(pin);
+                               addPin(pin);
+                       }
+               outputPin.setRelPos(width, inputCount * pinDistance / 2);
+       }
+
+       public Pin getOutputPin()
+       {
+               return outputPin;
+       }
+
+       public List<Pin> getInputPins()
+       {
+               return inputPinsUnmodifiable;
+       }
+
+       @Override
+       public void render(GeneralGC gc, Rectangle visibleRegion)
+       {
+               double posX = getBounds().x;
+               double posY = getBounds().y;
+
+               double height = inputPins.size() * pinDistance;
+               gc.drawRectangle(posX, posY, rectWidth, height);
+               Font oldFont = gc.getFont();
+               Font labelFont = new Font(oldFont.getName(), fontHeight, oldFont.getStyle());
+               gc.setFont(labelFont);
+               Point textExtent = gc.textExtent(label);
+               gc.drawText(label, posX + (rectWidth - textExtent.x) / 2, posY + (height - textExtent.y) / 2, true);
+               gc.setFont(oldFont);
+               if (isInverted)
+                       gc.drawOval(posX + rectWidth, posY + (height - invertedCircleDiam) / 2, invertedCircleDiam, invertedCircleDiam);
+       }
+}
\ No newline at end of file
index c2f03ee..6bcbd1c 100644 (file)
@@ -14,17 +14,21 @@ import net.haspamelodica.swt.helper.swtobjectwrappers.Point;
 public class GUIWire
 {
        private final ViewModel model;
+       public final int logicWidth;
        private Pin pin1;
        private Pin pin2;
        private double[] path;
 
-       private final List<Consumer<? super GUIWire>> wireChangedListeners;
+       private final List<Consumer<? super GUIWire>> wireLookChangedListeners;
 
        private ReadEnd end;
 
        public GUIWire(ViewModel model, Pin pin1, Pin pin2, Point... path)
        {
                this.model = model;
+               this.logicWidth = pin1.logicWidth;
+               if (pin2.logicWidth != pin1.logicWidth)
+                       throw new IllegalArgumentException("Can't connect pins of different logic width");
                this.path = new double[path.length * 2 + 4];
                for (int srcI = 0, dstI = 2; srcI < path.length; srcI++, dstI += 2)
                {
@@ -35,7 +39,7 @@ public class GUIWire
                this.pin1 = pin1;
                this.pin2 = pin2;
 
-               wireChangedListeners = new ArrayList<>();
+               wireLookChangedListeners = new ArrayList<>();
 
                pin1.addPinMovedListener(p -> pin1Moved());
                pin2.addPinMovedListener(p -> pin2Moved());
@@ -72,15 +76,25 @@ public class GUIWire
        public void setLogicModelBinding(ReadEnd end)
        {
                this.end = end;
-               end.addObserver((i, o) -> callWireChangedListeners());
+               end.addObserver((i, o) -> callWireLookChangedListeners());
+       }
+
+       public Pin getPin1()
+       {
+               return pin1;
+       }
+
+       public Pin getPin2()
+       {
+               return pin2;
        }
 
        // @formatter:off
-       public void addWireChangedListener   (Consumer<? super GUIWire> listener) {wireChangedListeners.add   (listener);}
+       public void addWireLookChangedListener   (Consumer<? super GUIWire> listener) {wireLookChangedListeners.add   (listener);}
 
-       public void removeWireChangedListener(Consumer<? super GUIWire> listener) {wireChangedListeners.remove(listener);}
+       public void removeWireLookChangedListener(Consumer<? super GUIWire> listener) {wireLookChangedListeners.remove(listener);}
 
-       private void callWireChangedListeners() {wireChangedListeners.forEach(l -> l.accept(this));}
+       private void callWireLookChangedListeners() {wireLookChangedListeners.forEach(l -> l.accept(this));}
        // @formatter:on
 
 }
\ No newline at end of file
index 673b257..949e7d7 100644 (file)
@@ -4,9 +4,9 @@ import era.mi.gui.model.components.GUIComponent;
 
 public class MovablePin extends Pin
 {
-       public MovablePin(GUIComponent component, double relX, double relY)
+       public MovablePin(GUIComponent component, int logicWidth, double relX, double relY)
        {
-               super(component, relX, relY);
+               super(component, logicWidth, relX, relY);
        }
 
        @Override
index 44ea374..abafc07 100644 (file)
@@ -11,15 +11,17 @@ import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 public class Pin
 {
        public final GUIComponent component;
+       public final int logicWidth;
 
        protected double relX;
        protected double relY;
 
        private final List<Consumer<? super Pin>> pinMovedListeners;
 
-       public Pin(GUIComponent component, double relX, double relY)
+       public Pin(GUIComponent component, int logicWidth, double relX, double relY)
        {
                this.component = component;
+               this.logicWidth = logicWidth;
                this.relX = relX;
                this.relY = relY;
 
index ebe30c3..73d98f5 100644 (file)
@@ -11,12 +11,14 @@ import net.haspamelodica.swt.helper.swtobjectwrappers.Rectangle;
 public class WireCrossPoint extends GUIComponent
 {
        private ReadEnd end;
+       private final int logicWidth;
 
-       public WireCrossPoint(ViewModel model)
+       public WireCrossPoint(ViewModel model, int logicWidth)
        {
                super(model);
+               this.logicWidth = logicWidth;
                setSize(0, 0);
-               addPin(new Pin(this, 0, 0));
+               addPin(new Pin(this, logicWidth, 0, 0));
        }
 
        @Override
@@ -28,6 +30,11 @@ public class WireCrossPoint extends GUIComponent
        public void setLogicModelBinding(ReadEnd end)
        {
                this.end = end;
-               end.addObserver((i, o) -> callComponentChangedListeners());
+               end.addObserver((i, o) -> callComponentLookChangedListeners());
+       }
+
+       public int getLogicWidth()
+       {
+               return logicWidth;
        }
 }
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/modeladapter/LogicModelParameters.java b/LogicUI/src/era/mi/gui/modeladapter/LogicModelParameters.java
new file mode 100644 (file)
index 0000000..435f708
--- /dev/null
@@ -0,0 +1,7 @@
+package era.mi.gui.modeladapter;
+
+public class LogicModelParameters
+{
+       public int wireTravelTime;
+       public int gateProcessTime;
+}
\ No newline at end of file
index f005a80..c64ae97 100644 (file)
@@ -1,6 +1,139 @@
 package era.mi.gui.modeladapter;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import era.mi.gui.model.ViewModel;
+import era.mi.gui.model.components.GUIAndGate;
+import era.mi.gui.model.components.GUIComponent;
+import era.mi.gui.model.components.GUINotGate;
+import era.mi.gui.model.components.GUIOrGate;
+import era.mi.gui.model.wires.GUIWire;
+import era.mi.gui.model.wires.Pin;
+import era.mi.gui.model.wires.WireCrossPoint;
+import era.mi.gui.modeladapter.componentadapters.ComponentAdapter;
+import era.mi.gui.modeladapter.componentadapters.SimpleGateAdapter;
+import era.mi.logic.components.Component;
+import era.mi.logic.components.gates.AndGate;
+import era.mi.logic.components.gates.NotGate;
+import era.mi.logic.components.gates.OrGate;
+import era.mi.logic.timeline.Timeline;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.ReadEnd;
+
 public class ViewLogicModelAdapter
 {
+       private final static Map<Class<? extends GUIComponent>, ComponentAdapter<? extends GUIComponent>> componentAdapters;
+       static
+       {
+               Map<Class<? extends GUIComponent>, ComponentAdapter<? extends GUIComponent>> componentAdaptersModifiable = new HashMap<>();
+               componentAdaptersModifiable.put(GUIOrGate.class, new SimpleGateAdapter(OrGate::new));
+               componentAdaptersModifiable.put(GUIAndGate.class, new SimpleGateAdapter(AndGate::new));
+               componentAdaptersModifiable.put(GUINotGate.class, new SimpleGateAdapter((t, p, o, i) -> new NotGate(t, p, i[0], o)));
+               // TODO list all "primitive" adapters here
+               componentAdapters = Collections.unmodifiableMap(componentAdaptersModifiable);
+       }
+
+       public static Timeline convert(ViewModel viewModel, LogicModelParameters params)
+       {
+               // TODO replace Timeline with LogicModel as soon as it exists
+               Timeline timeline = new Timeline(10);
+
+               Map<Pin, Wire> logicWiresPerPin = convertWires(
+                               viewModel.getComponents().stream().flatMap(component -> component.getPins().stream()).collect(Collectors.toSet()),
+                               viewModel.getWires(), params, timeline);
+               Map<Pin, Wire> logicWiresPerPinUnmodifiable = Collections.unmodifiableMap(logicWiresPerPin);
+
+               Map<GUIComponent, Component> oneToOneComponents = new HashMap<>();
+               for (GUIComponent guiComp : viewModel.getComponents())
+               {
+                       // WireCrossPoints just vanish
+                       if (!(guiComp instanceof WireCrossPoint))
+                               oneToOneComponents.put(guiComp, createAndLinkComponent(timeline, params, guiComp, logicWiresPerPinUnmodifiable,
+                                               componentAdapters.get(guiComp.getClass())));
+               }
+
+               // TODO handle complex components
+
+               List<Component> logicComponents = new ArrayList<>();
+               logicComponents.addAll(oneToOneComponents.values());
+
+               return timeline;
+       }
+
+       private static Map<Pin, Wire> convertWires(Set<Pin> allPins, List<GUIWire> wires, LogicModelParameters params, Timeline timeline)
+       {
+               Map<Pin, Set<Pin>> connectedPinGroups = getConnectedPinGroups(allPins, wires);
+               Map<Pin, Wire> logicWiresPerPin = createLogicWires(params, timeline, connectedPinGroups);
+               setGUIWiresLogicModelBinding(wires, logicWiresPerPin);
+               return logicWiresPerPin;
+       }
+
+       private static Map<Pin, Wire> createLogicWires(LogicModelParameters params, Timeline timeline, Map<Pin, Set<Pin>> connectedPinGroups)
+       {
+               Map<Pin, Wire> logicWiresPerPin = new HashMap<>();
+               Map<Set<Pin>, Wire> logicWiresPerPinGroup = new HashMap<>();
+               for (Entry<Pin, Set<Pin>> e : connectedPinGroups.entrySet())
+                       logicWiresPerPin.put(e.getKey(), logicWiresPerPinGroup.computeIfAbsent(e.getValue(),
+                                       set -> new Wire(timeline, e.getKey().logicWidth, params.wireTravelTime)));
+               return logicWiresPerPin;
+       }
+
+       private static void setGUIWiresLogicModelBinding(List<GUIWire> wires, Map<Pin, Wire> logicWiresPerPin)
+       {
+               Map<Wire, ReadEnd> guiWireSharedReadEnd = logicWiresPerPin.values().stream().distinct()
+                               .collect(Collectors.toMap(Function.identity(), Wire::createReadOnlyEnd));
+               for (GUIWire guiWire : wires)
+                       guiWire.setLogicModelBinding(guiWireSharedReadEnd.get(logicWiresPerPin.get(guiWire.getPin1())));
+       }
+
+       private static Map<Pin, Set<Pin>> getConnectedPinGroups(Set<Pin> allPins, List<GUIWire> wires)
+       {
+               Map<Pin, Set<Pin>> connectedPinsPerPin = new HashMap<>();
+
+               for (Pin p : allPins)
+               {
+                       HashSet<Pin> connectedPins = new HashSet<>();
+                       connectedPins.add(p);
+                       connectedPinsPerPin.put(p, connectedPins);
+               }
+
+               wires.forEach(wire ->
+               {
+                       Pin pin1 = wire.getPin1();
+                       Pin pin2 = wire.getPin2();
+
+                       Set<Pin> pin1ConnectedPins = connectedPinsPerPin.get(pin1);
+                       Set<Pin> pin2ConnectedPins = connectedPinsPerPin.get(pin2);
+
+                       pin1ConnectedPins.addAll(pin2ConnectedPins);
+                       pin1ConnectedPins.add(pin1);
+                       pin1ConnectedPins.add(pin2);
+
+                       pin2ConnectedPins.forEach(pin -> connectedPinsPerPin.put(pin, pin1ConnectedPins));
+               });
+               return connectedPinsPerPin;
+       }
+
+       @SuppressWarnings("unchecked")
+       private static <G extends GUIComponent> Component createAndLinkComponent(Timeline timeline, LogicModelParameters params,
+                       GUIComponent guiComponent, Map<Pin, Wire> logicWiresPerPin, ComponentAdapter<G> adapter)
+       {
+               if (adapter == null)
+                       throw new IllegalArgumentException("Unknown component class: " + guiComponent.getClass());
+               return adapter.createAndLinkComponent(timeline, params, (G) guiComponent, logicWiresPerPin);
+       }
 
+       private ViewLogicModelAdapter()
+       {
+               throw new UnsupportedOperationException("No ViewLogicModelConverter instances");
+       }
 }
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/modeladapter/componentadapters/ComponentAdapter.java b/LogicUI/src/era/mi/gui/modeladapter/componentadapters/ComponentAdapter.java
new file mode 100644 (file)
index 0000000..8598fa8
--- /dev/null
@@ -0,0 +1,16 @@
+package era.mi.gui.modeladapter.componentadapters;
+
+import java.util.Map;
+
+import era.mi.gui.model.components.GUIComponent;
+import era.mi.gui.model.wires.Pin;
+import era.mi.gui.modeladapter.LogicModelParameters;
+import era.mi.logic.components.Component;
+import era.mi.logic.timeline.Timeline;
+import era.mi.logic.wires.Wire;
+
+public interface ComponentAdapter<G extends GUIComponent>
+{
+       public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, G guiComponent,
+                       Map<Pin, Wire> logicWiresPerPin);
+}
\ No newline at end of file
diff --git a/LogicUI/src/era/mi/gui/modeladapter/componentadapters/SimpleGateAdapter.java b/LogicUI/src/era/mi/gui/modeladapter/componentadapters/SimpleGateAdapter.java
new file mode 100644 (file)
index 0000000..e256ff0
--- /dev/null
@@ -0,0 +1,40 @@
+package era.mi.gui.modeladapter.componentadapters;
+
+import java.util.List;
+import java.util.Map;
+
+import era.mi.gui.model.components.SimpleRectangularGUIGate;
+import era.mi.gui.model.wires.Pin;
+import era.mi.gui.modeladapter.LogicModelParameters;
+import era.mi.logic.components.Component;
+import era.mi.logic.timeline.Timeline;
+import era.mi.logic.wires.Wire;
+import era.mi.logic.wires.Wire.ReadEnd;
+import era.mi.logic.wires.Wire.ReadWriteEnd;
+
+public class SimpleGateAdapter implements ComponentAdapter<SimpleRectangularGUIGate>
+{
+       private final ComponentConstructor constructor;
+
+       public SimpleGateAdapter(ComponentConstructor constructor)
+       {
+               this.constructor = constructor;
+       }
+
+       @Override
+       public Component createAndLinkComponent(Timeline timeline, LogicModelParameters params, SimpleRectangularGUIGate guiComponent,
+                       Map<Pin, Wire> logicWiresPerPin)
+       {
+               ReadWriteEnd out = logicWiresPerPin.get(guiComponent.getOutputPin()).createReadWriteEnd();
+               List<Pin> inputPins = guiComponent.getInputPins();
+               ReadEnd[] ins = new ReadEnd[inputPins.size()];
+               for (int i = 0; i < inputPins.size(); i++)
+                       ins[i] = logicWiresPerPin.get(inputPins.get(i)).createReadOnlyEnd();
+               return constructor.newComponent(timeline, params.gateProcessTime, out, ins);
+       }
+
+       public static interface ComponentConstructor
+       {
+               public Component newComponent(Timeline timeline, int processTime, ReadWriteEnd out, ReadEnd[] ins);
+       }
+}
\ No newline at end of file