From 4feda6f709c430e5f3b1d5e8c1ef0c7b157152d0 Mon Sep 17 00:00:00 2001 From: Stephan Richter Date: Wed, 16 Jun 2021 14:10:39 +0200 Subject: [PATCH] separated decoder settings from locomotive --- pom.xml | 2 +- .../translations/Application.de.translation | 13 ++- .../de/srsoftware/web4rail/Application.java | 5 +- .../de/srsoftware/web4rail/BaseClass.java | 7 +- .../de/srsoftware/web4rail/Constants.java | 1 + .../srsoftware/web4rail/devices/Decoder.java | 106 ++++++++++++++++-- .../de/srsoftware/web4rail/moving/Car.java | 2 +- .../web4rail/moving/Locomotive.java | 103 +++++++++-------- 8 files changed, 176 insertions(+), 63 deletions(-) diff --git a/pom.xml b/pom.xml index 1377c14..524e03d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 de.srsoftware web4rail - 1.4.34 + 1.4.35 Web4Rail jar Java Model Railway Control diff --git a/resources/translations/Application.de.translation b/resources/translations/Application.de.translation index be099de..339aebe 100644 --- a/resources/translations/Application.de.translation +++ b/resources/translations/Application.de.translation @@ -136,6 +136,7 @@ disabled : deaktiviert disable {} : {} deaktivieren disabled routes : deaktivierte Fahrstraßen DisableEnableBlock : Block (de)aktivieren +dismount : ausbauen Display "{}" on {}. : „{}“ auf {} anzeigen. Do you know, what you are doing? : Weißt du, was du da tust? driven distance : zurückgelegte Strecke @@ -227,16 +228,20 @@ mileage : Laufleistung Minimum delay : minimale Verzögerung Minimum and maximum times (in Miliseconds) trains with the respective tag have to wait in this block. : Minamle und maximale Block-Haltezeit (in Millisekunden) für Züge mit der entsprchender Markierung. minimum starting voltage vmin : Mindestanfahrspannung vmin +Mounted into "{}". : In "{}" eingebaut. +Mounted decoder "{}". : Decoder "{}" eingebaut. Move tiles : Kacheln verschieben move up : nach oben schieben name : Name new car : neuer Waggon new contact : neuer Kontakt +new decoder : neuer Decoder new direction : neue Fahrtrichtung new locomotive : neue Lok new tag : neue Markierung new train : neuer Zug No : keine +no decoder : kein Decoder No direct route from {} to {} : keine direkte Verbindung von {} zu {} No free routes from {} : keine Route von {} frei NORTH : Norden @@ -272,6 +277,8 @@ Plan updated. : Plan aktualisiert. Port for state {} : Anschluss für Status {} PreserveRoute : Anschlußroute vorwählen Programming : Programmierung +prgramming track : Programmier-Gleis +program on main : Hauptgleis-Programmierung Properties : Eigenschaften Properties of {} : Eigenschaften von {} Properties of {} @ ({},{}) : Eigenschaften von {} @ ({},{}) @@ -285,6 +292,8 @@ Relay : Relais Relay/Signal/Turnout : Relais/Signal/Weiche Remove tag "{}" from train : Markierung "{}" von Zug entfernen Removed {} : {} gelöscht +Removed decoder "{}". : Decoder „{}“ ausgebaut. +Removed decoder from "{}". : Decoder aus „{}“ entfernt. Removed train "{}" : Zug „{}“ gelöscht rename : umbenennen Rename plan : Plan umbenennen @@ -436,8 +445,10 @@ TurnoutRS : WeicheRS TurnoutRW : WeicheRW Turnouts : Weichen turn within train : innerhalb des Zugs drehen -Turns the train, as if it went through a loop. : Dreht den ZUg, als wenn er eine Wendeschleife passiert hätte. +Turns the train, as if it went through a loop. : Dreht den ZUg, als wenn er eine Wendeschleife passiert hätte. +Type : Typ Unknown action\: {} : Unbekannte Aktion: {} +Unknown decoder type : Unbekannter Decoder-Typ Use negative number to count from end. : Nutze negative Nummern, um von Ende zu zählen. unset : ungesetzt update : aktualisieren diff --git a/src/main/java/de/srsoftware/web4rail/Application.java b/src/main/java/de/srsoftware/web4rail/Application.java index c525e6e..51a76da 100644 --- a/src/main/java/de/srsoftware/web4rail/Application.java +++ b/src/main/java/de/srsoftware/web4rail/Application.java @@ -25,6 +25,7 @@ import de.srsoftware.localconfig.Configuration; import de.srsoftware.tools.Tag; import de.srsoftware.web4rail.actions.ActionList; import de.srsoftware.web4rail.conditions.Condition; +import de.srsoftware.web4rail.devices.Decoder; import de.srsoftware.web4rail.moving.Car; import de.srsoftware.web4rail.moving.Locomotive; import de.srsoftware.web4rail.moving.Train; @@ -124,8 +125,10 @@ public class Application extends BaseClass{ return Contact.process(params); case REALM_CONDITION: return Condition.action(params,plan); - case REALM_CU: + case REALM_CU: return plan.controlUnit().process(params); + case REALM_DECODER: + return Decoder.action(params); case REALM_HISTORY: return History.action(params); case REALM_LOCO: diff --git a/src/main/java/de/srsoftware/web4rail/BaseClass.java b/src/main/java/de/srsoftware/web4rail/BaseClass.java index ddfa88a..b47b40f 100644 --- a/src/main/java/de/srsoftware/web4rail/BaseClass.java +++ b/src/main/java/de/srsoftware/web4rail/BaseClass.java @@ -24,6 +24,7 @@ import de.srsoftware.web4rail.History.LogEntry; import de.srsoftware.web4rail.Plan.Direction; import de.srsoftware.web4rail.actions.Action; import de.srsoftware.web4rail.conditions.Condition; +import de.srsoftware.web4rail.devices.Decoder; import de.srsoftware.web4rail.moving.Car; import de.srsoftware.web4rail.moving.Locomotive; import de.srsoftware.web4rail.moving.Train; @@ -566,6 +567,7 @@ public abstract class BaseClass implements Constants{ public String realm() { if (this instanceof Contact) return REALM_CONTACT; + if (this instanceof Decoder) return REALM_DECODER; if (this instanceof Tile) return REALM_PLAN; if (this instanceof Locomotive) return REALM_LOCO; @@ -588,9 +590,10 @@ public abstract class BaseClass implements Constants{ return props; } - public BaseClass register() { + @SuppressWarnings("unchecked") + public T register() { registry.put(id(),this); - return this; + return (T) this; } public BaseClass remove() { diff --git a/src/main/java/de/srsoftware/web4rail/Constants.java b/src/main/java/de/srsoftware/web4rail/Constants.java index a9d2921..4ab1a12 100644 --- a/src/main/java/de/srsoftware/web4rail/Constants.java +++ b/src/main/java/de/srsoftware/web4rail/Constants.java @@ -48,6 +48,7 @@ public interface Constants { public static final String REALM_CONDITION = "condition"; public static final String REALM_CONTACT = "contact"; public static final String REALM_CU = "cu"; + public static final String REALM_DECODER = "decoder"; public static final String REALM_HISTORY = "history"; public static final String REALM_LOCO = "loco"; public static final String REALM_MAINTENANCE = "maintenance"; diff --git a/src/main/java/de/srsoftware/web4rail/devices/Decoder.java b/src/main/java/de/srsoftware/web4rail/devices/Decoder.java index 24a7b6c..1927ad7 100644 --- a/src/main/java/de/srsoftware/web4rail/devices/Decoder.java +++ b/src/main/java/de/srsoftware/web4rail/devices/Decoder.java @@ -1,27 +1,30 @@ package de.srsoftware.web4rail.devices; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; -import java.util.Map.Entry; import java.util.concurrent.TimeoutException; import org.json.JSONObject; import de.srsoftware.tools.Tag; -import de.srsoftware.tools.Tools; import de.srsoftware.web4rail.BaseClass; import de.srsoftware.web4rail.Command; import de.srsoftware.web4rail.Command.Reply; +import de.srsoftware.web4rail.Constants; +import de.srsoftware.web4rail.Protocol; +import de.srsoftware.web4rail.moving.Locomotive; import de.srsoftware.web4rail.tags.Button; import de.srsoftware.web4rail.tags.Fieldset; import de.srsoftware.web4rail.tags.Form; import de.srsoftware.web4rail.tags.Input; import de.srsoftware.web4rail.tags.Radio; +import de.srsoftware.web4rail.tags.Select; import de.srsoftware.web4rail.tags.Table; import de.srsoftware.web4rail.tags.Window; -import de.srsoftware.web4rail.Constants; -import de.srsoftware.web4rail.Protocol; public class Decoder extends BaseClass implements Constants, Device { @@ -38,12 +41,43 @@ public class Decoder extends BaseClass implements Constants, Device { private static final String TRACK = "track"; private static final String VALUE = "val"; private static final String CV = "cv"; + private String type; + private Locomotive loco; + public static Object action(HashMap params) { + Decoder decoder = BaseClass.get(Id.from(params)); + switch (params.get(Constants.ACTION)) { + case ACTION_DECOUPLE: + return decoder.dismount(); + case ACTION_PROGRAM: + return decoder.program(params); + case ACTION_PROPS: + return decoder.properties(); + case ACTION_UPDATE: + return decoder.update(params); + } + + String message = BaseClass.t("Unknown action: {}",params.get(Constants.ACTION)); + return (BaseClass.isNull(decoder)) ? message : decoder.properties(message); + } + + private Window dismount() { + if (isNull(loco)) return properties(); + Locomotive locomotive = loco; + locomotive.removeDecoder(this); + loco = null; + addLogEntry(t("Removed decoder from \"{}\".",locomotive)); + return locomotive.properties(); + } @Override public int address() { if (isNull(address)) address = cvs.get(CV_ADDR); - return address; + return isNull(address) ? 3 : address; + } + + public Button button() { + return super.button(type(),Map.of(REALM,REALM_DECODER)); } public void init() { @@ -84,13 +118,14 @@ public class Decoder extends BaseClass implements Constants, Device { JSONObject json = super.json(); json.put(CVS, cvs); json.put(PROTOCOL, proto); + json.put(TYPE, type); return json; } - + @Override public Tag link(String... args) { - Tools.notImplemented("Decoder.link(…)"); - return new Tag("span").content("[[Decoder.link() not implemented]]"); + // TODO Auto-generated method stub + return null; } @Override @@ -101,9 +136,21 @@ public class Decoder extends BaseClass implements Constants, Device { JSONObject jCvs = json.getJSONObject(CVS); for (String key : jCvs.keySet()) cvs.put(Integer.parseInt(key),jCvs.getInt(key)); } + if (json.has(TYPE)) type = json.getString(TYPE); return this; } + private Window program(HashMap params) { + String error = null; + if (params.get(ACTION).equals(ACTION_PROGRAM)) try { + int cv = Integer.parseInt(params.get(CV)); + int val = Integer.parseInt(params.get(VALUE)); + boolean pom = !params.get(MODE).equals(TRACK); + error = program(cv,val,pom); + } catch (NumberFormatException e) {} + return properties(error); + } + private String program(int cv,int val,boolean pom) { if (cv != 0) { if (val < 0) { @@ -132,7 +179,7 @@ public class Decoder extends BaseClass implements Constants, Device { Fieldset fieldset = new Fieldset(t("Programming")).id("props-cv"); Form form = new Form("cv-form"); - new Input(REALM,REALM_LOCO).hideIn(form); + new Input(REALM,REALM_DECODER).hideIn(form); new Input(ID,id()).hideIn(form); new Input(ACTION,ACTION_PROGRAM).hideIn(form); @@ -161,12 +208,14 @@ public class Decoder extends BaseClass implements Constants, Device { @Override protected Window properties(List
preForm, FormInput formInputs, List
postForm, String... errorMessages) { + formInputs.add(t("Type"),new Input(TYPE,type())); Tag div = new Tag("div"); for (Protocol proto : Protocol.values()) { new Radio(PROTOCOL, proto.toString(), t(proto.toString()), proto == this.proto).addTo(div); } formInputs.add(t("Protocol"),div); - formInputs.add(t("Address"),new Input(ADDRESS, address).numeric()); + formInputs.add(t("Address"),new Tag("span").content(""+address())); + if (isSet(loco)) formInputs.add(t("Locomotive"),loco.button(loco.name())); postForm.add(programming()); return super.properties(preForm, formInputs, postForm, errorMessages); } @@ -175,6 +224,25 @@ public class Decoder extends BaseClass implements Constants, Device { return proto; } + public static Select selector(boolean freeOnly) { + Select selector = new Select(REALM_DECODER); + List decoders = BaseClass.listElements(Decoder.class); + selector.addOption(-1,t("no decoder")); + selector.addOption(0,t("new decoder")); + for (Decoder d: decoders) { + if (freeOnly && isSet(d.loco)) continue; + selector.addOption(d.id(), d); + } + return selector; + } + + public Decoder setLoco(Locomotive locomotive, boolean log) { + loco = locomotive; + if (log) addLogEntry(t("Mounted into \"{}\".",loco)); + locomotive.setDecoder(this,log); + return this; + } + public void setProtocol(Protocol proto) { this.proto = proto; } @@ -201,6 +269,22 @@ public class Decoder extends BaseClass implements Constants, Device { } return ""; } + + @Override + public String toString() { + return type()+" ("+t("Address")+": "+address()+")"; + } + - + public String type() { + return isSet(type) ? type : t("Unknown decoder type"); + } + + @Override + protected Window update(HashMap params) { + super.update(params); + if (params.containsKey(TYPE)) type = params.get(TYPE); + if (params.containsKey(Device.PROTOCOL)) setProtocol(Protocol.valueOf(params.get(Device.PROTOCOL))); + return isSet(loco) ? loco.properties() : properties(); + } } diff --git a/src/main/java/de/srsoftware/web4rail/moving/Car.java b/src/main/java/de/srsoftware/web4rail/moving/Car.java index 518934d..8cf5674 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Car.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Car.java @@ -301,7 +301,7 @@ public class Car extends BaseClass implements Comparable{ return train().moveUp(this); } - String name(){ + public String name(){ return name; } diff --git a/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java b/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java index 47ddc3e..9bcef61 100644 --- a/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java +++ b/src/main/java/de/srsoftware/web4rail/moving/Locomotive.java @@ -5,29 +5,21 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeMap; import java.util.Vector; -import java.util.concurrent.TimeoutException; import org.json.JSONObject; import de.srsoftware.tools.Tag; import de.srsoftware.web4rail.BaseClass; import de.srsoftware.web4rail.Command; -import de.srsoftware.web4rail.Command.Reply; -import de.srsoftware.web4rail.devices.Decoder; -import de.srsoftware.web4rail.devices.Device; import de.srsoftware.web4rail.Constants; import de.srsoftware.web4rail.Plan; -import de.srsoftware.web4rail.Protocol; +import de.srsoftware.web4rail.devices.Decoder; import de.srsoftware.web4rail.tags.Button; import de.srsoftware.web4rail.tags.Fieldset; import de.srsoftware.web4rail.tags.Form; import de.srsoftware.web4rail.tags.Input; import de.srsoftware.web4rail.tags.Label; -import de.srsoftware.web4rail.tags.Radio; import de.srsoftware.web4rail.tags.Range; import de.srsoftware.web4rail.tags.Table; import de.srsoftware.web4rail.tags.Window; @@ -60,8 +52,6 @@ public class Locomotive extends Car implements Constants{ return loco.faster(Train.defaultSpeedStep); case ACTION_MOVE: return loco.moveUp(); -/* case ACTION_PROGRAM: - return loco.update(params); */ case ACTION_PROPS: return loco == null ? Locomotive.manager() : loco.properties(); case ACTION_SET_SPEED: @@ -211,10 +201,8 @@ public class Locomotive extends Car implements Constants{ public JSONObject json() { JSONObject json = super.json(); JSONObject loco = new JSONObject(); - //loco.put(PROTOCOL, proto); json.put(LOCOMOTIVE, loco); - //loco.put(CVS, cvs); - loco.put(Decoder.DECODER,decoder.json()); + if (isSet(decoder)) loco.put(Decoder.DECODER,decoder.json()); return json; } @@ -222,16 +210,20 @@ public class Locomotive extends Car implements Constants{ public Car load(JSONObject json) { super.load(json); if (json.has(LOCOMOTIVE)) { - if (isNull(decoder)) decoder = new Decoder(); JSONObject loco = json.getJSONObject(LOCOMOTIVE); - if (loco.has(Decoder.DECODER)) decoder.load(json.getJSONObject(Decoder.DECODER)); + if (loco.has(Decoder.DECODER)) { + if (isNull(decoder)) decoder = new Decoder(); + decoder.load(loco.getJSONObject(Decoder.DECODER)); + } if (loco.has(Decoder.CVS)) { // Legacy + if (isNull(decoder)) decoder = new Decoder(); + decoder.register(); JSONObject jCvs = loco.getJSONObject(Decoder.CVS); - for (String key : jCvs.keySet()) { - decoder.cvs.put(Integer.parseInt(key),jCvs.getInt(key)); - } + for (String key : jCvs.keySet()) decoder.cvs.put(Integer.parseInt(key),jCvs.getInt(key)); } + if (isSet(decoder)) decoder.setLoco(this,false); + } return this; } @@ -242,7 +234,7 @@ public class Locomotive extends Car implements Constants{ new Tag("p").content(t("Click on a name to edit the entry.")).addTo(win); - Table table = new Table().addHead(t("Stock ID"),t("Name"),t("Max. Speed",speedUnit),t("Protocol"),t("Address"),t("Length"),t("driven distance"),t("Tags")); + Table table = new Table().addHead(t("Stock ID"),t("Name"),t("Max. Speed",speedUnit),t("Address"),t("Decoder"),t("Length"),t("driven distance"),t("Tags")); List locos = BaseClass.listElements(Locomotive.class); locos.sort(Comparator.comparing(loco -> isSet(loco.decoder) ? loco.decoder.address() : 0)); locos.sort(Comparator.comparing(loco -> loco.stockId)); @@ -252,8 +244,8 @@ public class Locomotive extends Car implements Constants{ table.addRow(loco.stockId, loco.link(), maxSpeed+NBSP+speedUnit, - isSet(loco.decoder) ? loco.decoder.protocol() : null, isSet(loco.decoder) ? loco.decoder.address() : null, + isSet(loco.decoder) ? loco.decoder.button() : null, loco.length+NBSP+lengthUnit, loco.distanceCounter, String.join(", ", loco.tags())); @@ -279,19 +271,32 @@ public class Locomotive extends Car implements Constants{ protected Window properties(List
preForm, FormInput formInputs, List
postForm,String...errors) { preForm.add(cockpit(this)); Window props = super.properties(preForm, formInputs, postForm,errors); - if (isSet(decoder)) { Tag basicProps = props.children().stream().filter(tag -> BaseClass.PROPS_BASIC.equals(tag.get("id"))).findFirst().get(); Tag form = basicProps.children().stream().filter(tag -> tag.is("form")).findFirst().get(); Table table = (Table) form.children().stream().filter(tag -> tag.is("table")).findFirst().get(); - table.addRow(t("Decoder"),decoder.link()); + Tag div = new Tag("div"); + if (isSet(decoder)) { + decoder.button().addTo(div); + decoder.button(t("dismount"), Map.of(ACTION,ACTION_DECOUPLE)).addTo(div); + } else { + Decoder.selector(true).addTo(div); + } + table.addRow(t("Decoder"),div); Vector cols = table.children(); Tag lastRow = cols.lastElement(); cols.remove(cols.size()-1); cols.insertElementAt(lastRow, 5); - } return props; } + public void removeDecoder(Decoder decoder) { + if (this.decoder == decoder) { + addLogEntry(t("Removed decoder \"{}\".",decoder)); + this.decoder = null; + } + } + + private void queue() { if (isNull(decoder)) return; int step = decoder.protocol().steps * speed / (maxSpeedForward == 0 ? 100 : maxSpeedForward); @@ -306,6 +311,11 @@ public class Locomotive extends Car implements Constants{ }); } + public void setDecoder(Decoder newDecoder, boolean log) { + decoder = newDecoder; + if (log) addLogEntry(t("Mounted decoder \"{}\".",decoder)); + } + public String setFunction(int num, boolean active) { switch (num) { case 1: @@ -333,13 +343,15 @@ public class Locomotive extends Car implements Constants{ * @return */ public Tag setSpeed(int newSpeed) { - LOG.debug(this.detail()+".setSpeed({})",newSpeed); - speed = newSpeed; - if (speed > maxSpeedForward && maxSpeedForward > 0) speed = maxSpeed(); - if (speed < 0) speed = 0; - - queue(); - //plan.stream(t("Speed of {} set to {} {}.",this,speed,BaseClass.speedUnit)); + if (isSet(decoder)) { + LOG.debug(this.detail()+".setSpeed({})",newSpeed); + speed = newSpeed; + if (speed > maxSpeedForward && maxSpeedForward > 0) speed = maxSpeed(); + if (speed < 0) speed = 0; + + queue(); + //plan.stream(t("Speed of {} set to {} {}.",this,speed,BaseClass.speedUnit)); + } return properties(); } @@ -375,21 +387,20 @@ public class Locomotive extends Car implements Constants{ @Override protected Window update(HashMap params) { super.update(params); - if (isSet(decoder) && params.containsKey(Device.PROTOCOL)) decoder.setProtocol(Protocol.valueOf(params.get(Device.PROTOCOL))); - if (isSet(decoder) && params.containsKey(Device.ADDRESS)) { - int newAddress = Integer.parseInt(params.get(Device.ADDRESS)); - if (newAddress != decoder.address()) decoder.cvs.put(Decoder.CV_ADDR, newAddress); + if (params.containsKey(REALM_DECODER)) { + Id decoderId = Id.from(params,REALM_DECODER); + Decoder decoder = null; + switch (decoderId.toString()) { + case "-1": + break; + case "0": + decoder = new Decoder().register(); + break; + default: + decoder = Decoder.get(decoderId); + } + if (isSet(decoder)) decoder.setLoco(this,true); } - String error = null; - /*if (params.get(ACTION).equals(ACTION_PROGRAM)) try { - int cv = Integer.parseInt(params.get(CV)); - int val = Integer.parseInt(params.get(VALUE)); - boolean pom = !params.get(MODE).equals(TRACK); - error = program(cv,val,pom); - - } catch (NumberFormatException e) {}*/ - Window props = properties(); - if (isSet(error)) new Tag("span").content(error).addTo(props); - return props; + return properties(); } }