diff --git a/pom.xml b/pom.xml index 70b1264..1a071c2 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 de.srsoftware web4rail - 1.4.46 + 1.5.0 Web4Rail jar Java Model Railway Control diff --git a/src/main/java/de/srsoftware/web4rail/devices/Decoder.java b/src/main/java/de/srsoftware/web4rail/devices/Decoder.java index 8bb1c65..7f9c637 100644 --- a/src/main/java/de/srsoftware/web4rail/devices/Decoder.java +++ b/src/main/java/de/srsoftware/web4rail/devices/Decoder.java @@ -45,7 +45,6 @@ public class Decoder extends BaseClass implements Constants, Device { private static final String CV = "cv"; private static final String NUM_FUNCTIONS = "numFunctions"; private String type; - private Locomotive loco; private int numFunctions = 2; private int step; private boolean reverse; @@ -78,22 +77,26 @@ public class Decoder extends BaseClass implements Constants, Device { } private Window dismount() { - if (isNull(loco)) return properties(); - Locomotive locomotive = loco; + Locomotive locomotive = parent(); + if (isNull(locomotive)) return properties(); locomotive.removeDecoder(this); - loco = null; + parent(null); addLogEntry(t("Removed decoder from \"{}\".",locomotive)); return locomotive.properties(); } public StringBuilder functions() { - HashSet enabledFunctions = new HashSet<>(); - for (Function fun : loco.functions()) { - if (fun.enabled(this)) enabledFunctions.add(fun.index()); - } - + Locomotive loco = parent(); StringBuilder sb = new StringBuilder(); - for (int i=1; i<=numFunctions; i++) sb.append(" ").append(enabledFunctions.contains(i)?1:0); + + if (isSet(loco)) { + HashSet enabledFunctions = new HashSet<>(); + for (Function fun : loco.functions()) { + if (fun.enabled(this)) enabledFunctions.add(fun.index()); + } + + for (int i=1; i<=numFunctions; i++) sb.append(" ").append(enabledFunctions.contains(i)?1:0); + } return sb; } @@ -162,6 +165,12 @@ public class Decoder extends BaseClass implements Constants, Device { public int numFunctions() { return numFunctions ; } + + @Override + public Locomotive parent() { + BaseClass p = super.parent(); + return p instanceof Locomotive ? (Locomotive) p : null; + } private Window program(Params params) { String error = null; @@ -239,6 +248,7 @@ public class Decoder extends BaseClass implements Constants, Device { formInputs.add(t("Protocol"),div); formInputs.add(t("Address"),new Tag("span").content(""+address())); formInputs.add(t("Number of functions"),new Input(NUM_FUNCTIONS,numFunctions).numeric()); + Locomotive loco = parent(); if (isSet(loco)) formInputs.add(t("Locomotive"),loco.button(loco.name())); postForm.add(programming()); return super.properties(preForm, formInputs, postForm, errorMessages); @@ -270,15 +280,15 @@ public class Decoder extends BaseClass implements Constants, Device { selector.addOption(-1,t("no decoder")); selector.addOption(0,t("new decoder")); for (Decoder d: decoders) { - if (freeOnly && isSet(d.loco)) continue; + if (freeOnly && isSet(d.parent())) continue; selector.addOption(d.id(), d); } return selector; } public Decoder setLoco(Locomotive locomotive, boolean log) { - loco = locomotive; - if (log) addLogEntry(t("Mounted into \"{}\".",loco)); + parent(locomotive); + if (log) addLogEntry(t("Mounted into \"{}\".",locomotive)); locomotive.setDecoder(this,log); return this; } @@ -332,11 +342,7 @@ public class Decoder extends BaseClass implements Constants, Device { if (params.containsKey(TYPE)) type = params.getString(TYPE); if (params.containsKey(Device.PROTOCOL)) setProtocol(Protocol.valueOf(params.getString(Device.PROTOCOL))); if (params.containsKey(NUM_FUNCTIONS)) numFunctions = params.getInt(NUM_FUNCTIONS); + Locomotive loco = parent(); return isSet(loco) ? loco.properties() : properties(); } - - - - - } diff --git a/src/main/java/de/srsoftware/web4rail/functions/Function.java b/src/main/java/de/srsoftware/web4rail/functions/Function.java index 01ef4e3..4c8114f 100644 --- a/src/main/java/de/srsoftware/web4rail/functions/Function.java +++ b/src/main/java/de/srsoftware/web4rail/functions/Function.java @@ -49,6 +49,10 @@ public abstract class Function extends BaseClass{ return null; } + public boolean enabled() { + return enabled; + } + public boolean enabled(Decoder decoder) { return enabled; } @@ -101,8 +105,9 @@ public abstract class Function extends BaseClass{ return selector; } - public void setState(boolean enabled) { + public Function setState(boolean enabled) { this.enabled = enabled; + return this; } @Override diff --git a/src/main/java/de/srsoftware/web4rail/functions/FunctionList.java b/src/main/java/de/srsoftware/web4rail/functions/FunctionList.java index 9f62821..f8e9bef 100644 --- a/src/main/java/de/srsoftware/web4rail/functions/FunctionList.java +++ b/src/main/java/de/srsoftware/web4rail/functions/FunctionList.java @@ -44,4 +44,13 @@ public class FunctionList extends HashSet implements Constants{ stream().filter(fun -> name.equals(fun.name())).forEach(fun -> fun.setState(enabled)); return this; } + + + public HashSet with(String name) { + HashSet subset = new HashSet<>(); + for (Function f: this) { + if (f.name().equals(name)) subset.add(f); + } + return subset; + } } diff --git a/src/main/java/de/srsoftware/web4rail/functions/HeadLight.java b/src/main/java/de/srsoftware/web4rail/functions/HeadLight.java index 0080048..b0d0b94 100644 --- a/src/main/java/de/srsoftware/web4rail/functions/HeadLight.java +++ b/src/main/java/de/srsoftware/web4rail/functions/HeadLight.java @@ -1,5 +1,14 @@ package de.srsoftware.web4rail.functions; -public class HeadLight extends DirectedFunction { +import de.srsoftware.web4rail.devices.Decoder; +import de.srsoftware.web4rail.moving.Locomotive; +public class HeadLight extends DirectedFunction { + @Override + public boolean enabled(Decoder decoder) { + Locomotive loco = decoder.parent(); + if (isNull(loco) || !loco.isFirst()) return false; + boolean result = isSet(loco) && loco.isFirst() && super.enabled(decoder); + return result; + } } diff --git a/src/main/java/de/srsoftware/web4rail/functions/TailLight.java b/src/main/java/de/srsoftware/web4rail/functions/TailLight.java index 4fc926a..1a5fcb5 100644 --- a/src/main/java/de/srsoftware/web4rail/functions/TailLight.java +++ b/src/main/java/de/srsoftware/web4rail/functions/TailLight.java @@ -1,5 +1,13 @@ package de.srsoftware.web4rail.functions; -public class TailLight extends DirectedFunction { +import de.srsoftware.web4rail.devices.Decoder; +import de.srsoftware.web4rail.moving.Locomotive; +public class TailLight extends DirectedFunction { + @Override + public boolean enabled(Decoder decoder) { + Locomotive loco = decoder.parent(); + if (isNull(loco) || !loco.isLast()) return false; + return super.enabled(decoder); + } } diff --git a/src/main/java/de/srsoftware/web4rail/moving/Car.java b/src/main/java/de/srsoftware/web4rail/moving/Car.java index 5bf7636..4b6ff7e 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Car.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Car.java @@ -65,6 +65,8 @@ public class Car extends BaseClass implements Comparable{ protected int maxSpeedReverse = 0; protected boolean orientation = FORWARD; protected long distanceCounter = 0; + + private boolean isFirst,isLast; public Car(String name) { this(name,null); @@ -146,6 +148,24 @@ public class Car extends BaseClass implements Comparable{ public long drivenDistance() { return distanceCounter; } + + public boolean isFirst() { + return isFirst; + } + + public Car isFirst(boolean first) { + isFirst = first; + return this; + } + + public boolean isLast() { + return isLast; + } + + public Car isLast(boolean last) { + isLast = last; + return this; + } public JSONObject json() { JSONObject json = super.json(); diff --git a/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java b/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java index 5821f1d..9027c05 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java @@ -3,6 +3,7 @@ package de.srsoftware.web4rail.moving; import java.io.IOException; import java.util.Comparator; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Vector; @@ -100,23 +101,24 @@ public class Locomotive extends Car implements Constants{ public static Fieldset cockpit(BaseClass locoOrTrain) { int speed = 0; String realm = null; - Train train = null; + final Train train; final Locomotive loco; int maxSpeed = 0; String id = null; if (locoOrTrain instanceof Locomotive) { - loco = (Locomotive) locoOrTrain; + loco = (Locomotive) locoOrTrain; + train = null; realm = REALM_LOCO; speed = loco.speed; maxSpeed = loco.orientation ? loco.maxSpeedForward : loco.maxSpeedReverse; id = "loco_"+loco.id(); } else if (locoOrTrain instanceof Train) { + loco = null; train = (Train)locoOrTrain; realm = REALM_TRAIN; speed = train.speed; maxSpeed = train.maxSpeed(); id = "train_"+train.id(); - loco = null; } else return null; HashMap params = new HashMap(Map.of(REALM,realm,ID,locoOrTrain.id())); @@ -178,7 +180,12 @@ public class Locomotive extends Car implements Constants{ } if (isSet(train)) { - + train.functionNames().sorted().forEach(name -> { + Button btn = train.button(name, Map.of(ACTION,ACTION_TOGGLE_FUNCTION,FUNCTION,name)); + if (train.functionEnabled(name)) btn.clazz("active"); + btn.addTo(functions); + + }); } functions.addTo(fieldset); @@ -222,7 +229,7 @@ public class Locomotive extends Car implements Constants{ return new Button(t("Save"), form).addTo(form).addTo(fieldset); } - private Stream functionNames() { + public Stream functionNames() { return functions.stream().map(Function::name).sorted().distinct(); } @@ -230,6 +237,10 @@ public class Locomotive extends Car implements Constants{ return functions; } + public HashSet functions(String name){ + return functions.with(name); + } + @Override public JSONObject json() { JSONObject json = super.json(); diff --git a/src/main/java/de/srsoftware/web4rail/moving/Train.java b/src/main/java/de/srsoftware/web4rail/moving/Train.java index 37e3bb6..a73cf07 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Train.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Train.java @@ -7,7 +7,6 @@ import java.io.FileWriter; import java.io.IOException; import java.util.Collection; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -29,6 +28,7 @@ import de.srsoftware.web4rail.Params; import de.srsoftware.web4rail.Plan; import de.srsoftware.web4rail.Plan.Direction; import de.srsoftware.web4rail.Route; +import de.srsoftware.web4rail.functions.Function; import de.srsoftware.web4rail.tags.Button; import de.srsoftware.web4rail.tags.Checkbox; import de.srsoftware.web4rail.tags.Fieldset; @@ -100,7 +100,6 @@ public class Train extends BaseClass implements Comparable { private Route nextPreparedRoute; private BrakeProcess brake; - private HashMap functions = new HashMap<>(); public static Object action(Params params, Plan plan) throws IOException { String action = params.getString(ACTION); @@ -532,6 +531,16 @@ public class Train extends BaseClass implements Comparable { return setSpeed(speed+steps); } + public boolean functionEnabled(String name) { + return locos().flatMap( + loco -> loco.functions().stream().filter(f -> f.enabled() && f.name().equals(name)) + ).findAny().isPresent(); + } + + public Stream functionNames() { + return locos().flatMap(Locomotive::functionNames).distinct(); + } + private boolean hasLoco() { return locos().count() > 0; } @@ -1057,7 +1066,14 @@ public class Train extends BaseClass implements Comparable { private Object toggleFunction(Params params) { String name = params.getString(FUNCTION); String error = isNull(name) ? t("No function name passed to toggleFunction(…)") : null; - // TODO + boolean enable = !functionEnabled(name); + locos().forEach(loco -> { + Function any = null; + for (Function f : loco.functions(name)) { + any = f.setState(enable); + } + if (isSet(any)) loco.decoder().queue(); + }); return properties(error); } @@ -1074,12 +1090,18 @@ public class Train extends BaseClass implements Comparable { */ public Train turn() { LOG.debug("{}.turn()",this); - setSpeed(0); - for (Car car : cars) car.turn(); reverse(cars); + updateEnds(); + for (Car car : cars) car.turn(); return reverse(); } + private void updateEnds() { + for (Car car : cars) car.isFirst(false).isLast(false); + cars.firstElement().isFirst(true); + cars.lastElement().isLast(true); + } + public void unTrace(Tile tile) { if (isSet(trace)) trace.remove(tile); if (isSet(stuckTrace)) stuckTrace.remove(tile);