Browse Source

implemented signal functions

lookup-tables
Stephan Richter 5 years ago
parent
commit
e50bc039cd
  1. 2
      pom.xml
  2. 11
      resources/css/style.css
  3. 6
      resources/translations/Application.de.translation
  4. 97
      src/main/java/de/srsoftware/web4rail/Plan.java
  5. 13
      src/main/java/de/srsoftware/web4rail/Route.java
  6. 2
      src/main/java/de/srsoftware/web4rail/actions/SetSignal.java
  7. 187
      src/main/java/de/srsoftware/web4rail/tiles/Signal.java
  8. 2
      src/main/java/de/srsoftware/web4rail/tiles/Tile.java

2
pom.xml

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.srsoftware</groupId>
<artifactId>web4rail</artifactId>
<version>1.2.66</version>
<version>1.3.1</version>
<name>Web4Rail</name>
<packaging>jar</packaging>
<description>Java Model Railway Control</description>

11
resources/css/style.css

@ -191,12 +191,15 @@ h2{ @@ -191,12 +191,15 @@ h2{
stroke: red;
}
.signal.stop .sig_a{
.signal.red .sig_a{
fill: red;
}
.signal.go .sig_a{
.signal.green .sig_a{
fill: lime;
}
.signal.HL2 .sig_a{
fill: yellow;
}
.sig_b{
fill: black;
@ -373,3 +376,7 @@ svg.Block text{ @@ -373,3 +376,7 @@ svg.Block text{
clear:both;
border-radius: 0 5px 5px 5px;
}
#aspect-form td{
text-align: center;
}

6
resources/translations/Application.de.translation

@ -6,12 +6,14 @@ Action type\: : Aktions-Typ @@ -6,12 +6,14 @@ Action type\: : Aktions-Typ
Actions will only fire, if all conditions are fullfilled. : Aktionen werden nur ausgeführt, wenn alle Bedingungen erfüllt sind.
ActivateRoute : Route aktivieren
add : hinzufügen
add command for {} : Kommando für {} hinzufügen
Added {} : {} hinzugefügt
add action : Aktion hinzufügen
Add action to action list : Aktion zur Liste hinzufügen
add car\: : Waggon hinzufügen:
Add condition : Bedingung hinzufügen
add locomotive\: : Lok hinzufügen:
add new aspect : neues Signalbild hinzufügen
add new car : neuen Waggon anlegen
Add new custom field : neues benutzerdefiniertes Feld hinzufügen
add new locomotive : neue Lok anlegen
@ -27,6 +29,8 @@ Analyze may overwrite these routes! : Durch die Analyse können diese Fahrstraß @@ -27,6 +29,8 @@ Analyze may overwrite these routes! : Durch die Analyse können diese Fahrstraß
and : und
AndCondition : Und-Bedingung
Apply : Übernehmen
Aspect : Signalbild
Aspects : Signalbilder
Auto pilot : Autopilot
AutopilotActive : Autopilot aktiv
autopilot active for train : Autopilot für Zug aktiviert
@ -57,6 +61,7 @@ Click here to select display! : Hier klicken, um Anzeige auszuwählen! @@ -57,6 +61,7 @@ Click here to select display! : Hier klicken, um Anzeige auszuwählen!
Click here to select train! : Hier klicken, um Zug auszuwählen!
click here to setup contact : Hier klicken, um Kontakt auszuwählen
click here to setup relay : Hier klicken, um Relais einzurichten
click here to setup signal : Hier klicken, um Signal einzurichten
Click here to setup tag : Hier klicken, um Markierung anzugeben
click here to setup turnout : Hier klicken, um Weiche einzurichten
Click on a name to edit the entry. : Klicke auf einen Namen, um einen Eintrag zu bearbeiten.
@ -118,6 +123,7 @@ Function : Funktion @@ -118,6 +123,7 @@ Function : Funktion
Hardware settings : Hardware-Einstellungen
Height : Höhe
Help : Hilfe
Hold : an lassen
(id\: {}, length\: {}) : (Id: {}, Länge: {})
if ({})\: : falls ({}):
If checked, tiles behind the train are freed according to the length of the train and the tiles. If it is unchecked, tiles will not get free before route is finished.

97
src/main/java/de/srsoftware/web4rail/Plan.java

@ -60,6 +60,7 @@ import de.srsoftware.web4rail.tiles.EndW; @@ -60,6 +60,7 @@ import de.srsoftware.web4rail.tiles.EndW;
import de.srsoftware.web4rail.tiles.Eraser;
import de.srsoftware.web4rail.tiles.Relay;
import de.srsoftware.web4rail.tiles.Shadow;
import de.srsoftware.web4rail.tiles.Signal;
import de.srsoftware.web4rail.tiles.SignalE;
import de.srsoftware.web4rail.tiles.SignalN;
import de.srsoftware.web4rail.tiles.SignalS;
@ -186,6 +187,13 @@ public class Plan extends BaseClass{ @@ -186,6 +187,13 @@ public class Plan extends BaseClass{
return moveTile(params.get(DIRECTION),Id.from(params));
case ACTION_PROPS:
return properties(params);
case ACTION_POWER:
Signal signal = get(Id.from(params));
if (isSet(signal)) {
signal.state(params.get(Signal.STATE));
return signal.properties();
}
return null;
case ACTION_SAVE:
return saveTo(DEFAULT_NAME);
case ACTION_TIMES:
@ -317,6 +325,22 @@ public class Plan extends BaseClass{ @@ -317,6 +325,22 @@ public class Plan extends BaseClass{
tile.unregister();
stream("remove "+tile.id());
}
Fieldset editableProperties() {
Fieldset fieldset = new Fieldset(t("Editable properties"));
//new Tag("h4").content(t("Editable properties")).addTo(win);
Form form = new Form("plan-properties-form");
new Input(REALM,REALM_PLAN).hideIn(form);
new Input(ACTION,ACTION_UPDATE).hideIn(form);
new Input(LENGTH_UNIT, lengthUnit).addTo(new Label(t("Length unit")+":"+NBSP)).addTo(form);
new Input(SPEED_UNIT, speedUnit).addTo(new Label(t("Speed unit")+":"+NBSP)).addTo(form);
new Input(FINAL_SPEED, Route.endSpeed).addTo(new Label(t("Lower speed limit")+":"+NBSP)).attr("title", t("Final speed after breaking, before halting")).addTo(form);
new Checkbox(FREE_BEHIND_TRAIN, t("Free tiles behind train"), Route.freeBehindTrain).attr("title", t("If checked, tiles behind the train are freed according to the length of the train and the tiles. If it is unchecked, tiles will not get free before route is finished.")).addTo(form);
new Button(t("Save"), form).addTo(form);
form.addTo(fieldset);
return fieldset;
}
/**
* completes a given route during a call to {@link #analyze()}.
@ -634,43 +658,10 @@ public class Plan extends BaseClass{ @@ -634,43 +658,10 @@ public class Plan extends BaseClass{
Window win = new Window("plan-properties", t("Properties of {}",t("Plan")));
Fieldset fieldset = new Fieldset(t("Editable properties"));
//new Tag("h4").content(t("Editable properties")).addTo(win);
Form form = new Form("plan-properties-form");
new Input(REALM,REALM_PLAN).hideIn(form);
new Input(ACTION,ACTION_UPDATE).hideIn(form);
new Input(LENGTH_UNIT, lengthUnit).addTo(new Label(t("Length unit")+":"+NBSP)).addTo(form);
new Input(SPEED_UNIT, speedUnit).addTo(new Label(t("Speed unit")+":"+NBSP)).addTo(form);
new Input(FINAL_SPEED, Route.endSpeed).addTo(new Label(t("Lower speed limit")+":"+NBSP)).attr("title", t("Final speed after breaking, before halting")).addTo(form);
new Checkbox(FREE_BEHIND_TRAIN, t("Free tiles behind train"), Route.freeBehindTrain).attr("title", t("If checked, tiles behind the train are freed according to the length of the train and the tiles. If it is unchecked, tiles will not get free before route is finished.")).addTo(form);
new Button(t("Save"), form).addTo(form);
form.addTo(fieldset).addTo(win);
editableProperties().addTo(win);
relayProperties().addTo(win);
routeProperties().addTo(win);
fieldset = new Fieldset(t("Relays and Turnouts"));
Table table = new Table();
table.addHead(t("Address"),t("Relay/Turnout"));
List<Device> devices = BaseClass.listElements(Tile.class)
.stream()
.filter(tile -> tile instanceof Device )
.map(tile -> (Device) tile)
.sorted(Comparator.comparing(Device::address))
.collect(Collectors.toList());
for (Device device : devices) {
Tile tile = (Tile) device;
table.addRow(device.address(),tile.link(tile.toString()));
if (device.address() % 4 == 1) table.children().lastElement().clazz("group");
}
table.clazz("turnouts").addTo(fieldset).addTo(win);
fieldset = new Fieldset(t("Routes"));
table = new Table();
table.addHead(t("Name"),t("Start"),t("End"),t("Actions"));
List<Route> routes = BaseClass.listElements(Route.class);
for (Route route : routes) {
table.addRow(route.link("span",route.name()),route.link("span", route.startBlock()),route.link("span", route.endBlock()),plan.button(t("simplify name"), Map.of(ACTION,ACTION_AUTO,ROUTE,route.id().toString())));
}
table.clazz("turnouts").addTo(fieldset).addTo(win);
return win;
}
@ -697,11 +688,43 @@ public class Plan extends BaseClass{ @@ -697,11 +688,43 @@ public class Plan extends BaseClass{
return newRoute;
}
private Fieldset relayProperties() {
Fieldset fieldset = new Fieldset(t("Relays and Turnouts"));
Table table = new Table();
table.addHead(t("Address"),t("Relay/Turnout"));
List<Device> devices = BaseClass.listElements(Tile.class)
.stream()
.filter(tile -> tile instanceof Device )
.map(tile -> (Device) tile)
.sorted(Comparator.comparing(Device::address))
.collect(Collectors.toList());
for (Device device : devices) {
Tile tile = (Tile) device;
table.addRow(device.address(),tile.link(tile.toString()));
if (device.address() % 4 == 1) table.children().lastElement().clazz("group");
}
table.clazz("turnouts").addTo(fieldset);
return fieldset;
}
@Override
protected void removeChild(BaseClass child) {
if (child instanceof Tile) drop((Tile) child);
super.removeChild(child);
}
private Tag routeProperties() {
Fieldset fieldset = new Fieldset(t("Routes"));
Table table = new Table();
table.addHead(t("Name"),t("Start"),t("End"),t("Actions"));
List<Route> routes = BaseClass.listElements(Route.class);
for (Route route : routes) {
table.addRow(route.link("span",route.name()),route.link("span", route.startBlock()),route.link("span", route.endBlock()),plan.button(t("simplify name"), Map.of(ACTION,ACTION_AUTO,ROUTE,route.id().toString())));
}
table.clazz("turnouts").addTo(fieldset);
return fieldset;
}
public void save() throws IOException {
plan.stream(plan.saveTo("default"));
@ -864,7 +887,7 @@ public class Plan extends BaseClass{ @@ -864,7 +887,7 @@ public class Plan extends BaseClass{
public Object update(HashMap<String, String> params) {
super.update(params);
Tile tile = get(Id.from(params),true);
if (isSet(tile)) return tile.update(params);
if (isSet(tile)) return tile.update(params).properties();
if (params.containsKey(LENGTH_UNIT)) lengthUnit = params.get(LENGTH_UNIT);
if (params.containsKey(SPEED_UNIT)) speedUnit = params.get(SPEED_UNIT);

13
src/main/java/de/srsoftware/web4rail/Route.java

@ -344,7 +344,10 @@ public class Route extends BaseClass { @@ -344,7 +344,10 @@ public class Route extends BaseClass {
String trigger = nextToLastContact.trigger();
add(trigger,new BrakeStart(this));
add(trigger,new PreserveRoute(this));
for (Signal signal : signals) add(trigger,new SetSignal(this).set(signal).to(Signal.STOP));
Contact secondContact = contacts.get(1);
trigger = secondContact.trigger();
for (Signal signal : signals) add(trigger,new SetSignal(this).set(signal).to(Signal.RED));
}
if (!contacts.isEmpty()) {
Contact lastContact = contacts.lastElement();
@ -356,7 +359,7 @@ public class Route extends BaseClass { @@ -356,7 +359,7 @@ public class Route extends BaseClass {
Turnout.State state = entry.getValue();
add(ROUTE_SETUP,new SetTurnout(this).setTurnout(turnout).setState(state));
}
for (Signal signal : signals) add(ROUTE_START,new SetSignal(this).set(signal).to(Signal.GO));
for (Signal signal : signals) add(ROUTE_START,new SetSignal(this).set(signal).to(Signal.GREEN));
add(ROUTE_START,new SetSpeed(this).to(999));
return this;
}
@ -425,7 +428,7 @@ public class Route extends BaseClass { @@ -425,7 +428,7 @@ public class Route extends BaseClass {
public void finish() {
context.clear(); // prevent delayed actions from firing after route has finished
setSignals(Signal.STOP);
setSignals(Signal.RED);
for (Tile tile : path) try {
tile.unset(this);
} catch (IllegalArgumentException e) {}
@ -808,7 +811,7 @@ public class Route extends BaseClass { @@ -808,7 +811,7 @@ public class Route extends BaseClass {
public boolean reset() {
LOG.debug("{}.reset()",this);
setSignals(Signal.STOP);
setSignals(Signal.RED);
for (Tile tile : path) {
try {
tile.unset(this);
@ -859,7 +862,7 @@ public class Route extends BaseClass { @@ -859,7 +862,7 @@ public class Route extends BaseClass {
public boolean setSignals(String state) {
LOG.debug("{}.setSignals({})",this,state);
for (Signal signal : signals) {
if (!signal.state(isNull(state) ? Signal.GO : state)) return false;
if (!signal.state(isNull(state) ? Signal.GREEN : state)) return false;
}
return true;
}

2
src/main/java/de/srsoftware/web4rail/actions/SetSignal.java

@ -21,7 +21,7 @@ public class SetSignal extends Action { @@ -21,7 +21,7 @@ public class SetSignal extends Action {
private static final String SIGNAL = "signal";
private Signal signal = null;
private String state = Signal.STOP;
private String state = Signal.RED;
@Override
public boolean fire(Context context) {

187
src/main/java/de/srsoftware/web4rail/tiles/Signal.java

@ -1,22 +1,41 @@ @@ -1,22 +1,41 @@
package de.srsoftware.web4rail.tiles;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.TreeSet;
import java.util.Vector;
import de.srsoftware.tools.Tag;
import de.srsoftware.web4rail.Command;
import de.srsoftware.web4rail.Plan.Direction;
import de.srsoftware.web4rail.Window;
import de.srsoftware.web4rail.tags.Button;
import de.srsoftware.web4rail.tags.Checkbox;
import de.srsoftware.web4rail.tags.Fieldset;
import de.srsoftware.web4rail.tags.Form;
import de.srsoftware.web4rail.tags.Input;
import de.srsoftware.web4rail.tags.Table;
public abstract class Signal extends Tile {
public static final String STATE = "state";
public static final String STOP = "stop";
public static final String GO = "go";
public static final String RED = "red";
public static final String GREEN = "green";
public static final TreeSet<String> knownStates = new TreeSet<String>(List.of(RED, GREEN));
private final HashMap<String,HashSet<int[]>> aspects = new HashMap<String, HashSet<int[]>>();
private static final String ADDRESS = "addr";
private static final String HOLD = "hold";
private static final String NEW_ASPECT = "new_aspect";
private static final String ASPECTS = "aspects";
public static final TreeSet<String> knownStates = new TreeSet<String>(List.of(STOP, GO));
private String state = STOP;
private String state = RED;
public Signal() {
super();
@ -30,10 +49,104 @@ public abstract class Signal extends Tile { @@ -30,10 +49,104 @@ public abstract class Signal extends Tile {
}
public abstract boolean isAffectedFrom(Direction dir);
@Override
public JSONObject json() {
JSONObject json = super.json();
if (!aspects.isEmpty()) {
JSONObject jAspects = new JSONObject();
for (Entry<String, HashSet<int[]>> entry : aspects.entrySet()) {
String aspect = entry.getKey();
HashSet<int[]> commands = entry.getValue();
if (isSet(commands)) {
JSONArray jCommands = new JSONArray();
for (int[] data : commands) {
JSONObject jData = new JSONObject();
jData.put(ADDRESS, data[0]);
jData.put(PORT, data[1]);
jData.put(STATE, data[2]);
jData.put(HOLD, data[3]>0);
jCommands.put(jData);
}
jAspects.put(aspect, jCommands);
}
}
json.put(ASPECTS, jAspects);
}
return json;
}
@Override
public Tile load(JSONObject json) {
if (json.has(ASPECTS)) {
JSONObject jAspects = json.getJSONObject(ASPECTS);
for (String aspect : jAspects.keySet()) {
knownStates.add(aspect);
JSONArray jCommands = jAspects.getJSONArray(aspect);
jCommands.forEach(o -> {
if (o instanceof JSONObject) {
JSONObject d = (JSONObject) o;
int[] data = new int[] {d.getInt(ADDRESS),d.getInt(PORT),d.getInt(STATE),d.getBoolean(HOLD)?1:0};
HashSet<int[]> commands = aspects.get(aspect);
if (isNull(commands)) {
commands = new HashSet<int[]>();
aspects.put(aspect, commands);
}
commands.add(data);
}
});
}
}
return super.load(json);
}
@Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm) {
Fieldset aspectEditor = new Fieldset(t("Aspects"));
aspectEditor.attr(ID, "aspect-editor");
Form form = new Form("aspect-form");
new Input(REALM,REALM_PLAN).hideIn(form);
new Input(ACTION,ACTION_UPDATE).hideIn(form);
new Input(ID,id()).hideIn(form);
Table table = new Table();
table.addHead(t("Aspect"),t("Address"),t("Port"),t("State"),t("Hold"),t("Actions"));
for (String aspect : knownStates) {
HashSet<int[]> commands = aspects.get(aspect);
if (isSet(commands)) {
Tag link = this.link("span", (Object)aspect, Map.of(ACTION,ACTION_POWER,STATE,aspect));
for (int[] command : aspects.get(aspect)) {
Button delete = this.button(t("delete"), Map.of(ACTION,ACTION_UPDATE,ACTION_DROP+"-"+aspect,command[0]+"-"+command[1]+"-"+command[2]));
table.addRow(link,command[0],command[1],command[2],command[3]==1?"✓":"",delete);
}
}
}
for (String aspect : knownStates) {
table.addRow(t("add command for {}",aspect),new Input(ADDRESS+"-"+aspect, 0).numeric(),new Input(PORT+"-"+aspect,0).numeric(),new Input(STATE+"-"+aspect,0).numeric(),new Checkbox(HOLD+"-"+aspect, "", true));
}
Tag buttons = new Tag("div");
new Button(t("Save"), form).addTo(buttons);
table.addRow(t("add new aspect"),new Input(NEW_ASPECT),"","","",buttons);
table.addTo(form);
form.addTo(aspectEditor);
postForm.add(aspectEditor);
return super.properties(preForm, formInputs, postForm);
}
public boolean state(String state) {
LOG.debug("{}.state({})",this,state);
this.state = state;
public boolean state(String aspect) {
LOG.debug("{}.state({})",this,aspect);
this.state = aspect;
HashSet<int[]> commands = aspects.get(aspect);
if (isSet(commands)) {
for (int[] data : commands) {
Command cmd = new Command("SET {} GA "+data[0]+" "+data[1]+" "+data[2]+" "+(data[3]==1?-1:200));
LOG.debug("new Command: {}",cmd);
plan.controlUnit().queue(cmd);
}
}
plan.place(this);
return true;
}
@ -44,4 +157,62 @@ public abstract class Signal extends Tile { @@ -44,4 +157,62 @@ public abstract class Signal extends Tile {
tag.clazz(tag.get("class")+" "+state);
return tag;
}
@Override
public Tile update(HashMap<String, String> params) {
HashMap<String,int[]> newAspects = new HashMap<String, int[]>();
for (Entry<String, String> entry : params.entrySet()) {
String key = entry.getKey();
String val = entry.getValue().trim();
String[] parts = key.split("-");
if (parts.length>1) {
String subject = parts[0];
String aspect = parts[1];
int[] data = newAspects.get(aspect);
if (isNull(data)) {
data = new int[] {0,0,0,0};
newAspects.put(aspect,data);
}
switch (subject) {
case ADDRESS:
data[0] = Integer.parseInt(val); break;
case ACTION_DROP:
parts = val.split("-");
HashSet<int[]> commands = aspects.get(aspect);
if (isSet(commands)) for (int[] d : commands) {
if (d[0] != Integer.parseInt(parts[0])) continue;
if (d[1] != Integer.parseInt(parts[1])) continue;
if (d[2] != Integer.parseInt(parts[2])) continue;
commands.remove(d);
break;
}
break;
case HOLD:
data[3] = "on".equalsIgnoreCase(val)?1:0; break;
case PORT:
data[1] = Integer.parseInt(val); break;
case STATE:
data[2] = Integer.parseInt(val); break;
}
} else switch (key) {
case NEW_ASPECT:
if (!val.isEmpty()) knownStates.add(val); break;
}
}
for (Entry<String, int[]> entry : newAspects.entrySet()) {
String aspect = entry.getKey();
int[] data = entry.getValue();
if (data[0]==0) continue;
LOG.debug("{} : {} / {} / {}",entry.getKey(),data[0],data[1],data[2]);
HashSet<int[]> dataSet = aspects.get(aspect);
if (isNull(dataSet)) {
dataSet = new HashSet<int[]>();
aspects.put(aspect, dataSet);
}
aspects.get(aspect).add(data);
}
return super.update(params);
}
}

2
src/main/java/de/srsoftware/web4rail/tiles/Tile.java

@ -187,7 +187,7 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{ @@ -187,7 +187,7 @@ public abstract class Tile extends BaseClass implements Comparable<Tile>{
public Tag link(String...args) {
String tx = args.length<1 ? id()+NBSP : args[0];
String type = args.length<2 ? "span" : args[1];
return super.link(type, tx, Map.of(ACTION,ACTION_CLICK));
return super.link(type, (Object)tx, Map.of(ACTION,ACTION_CLICK));
}

Loading…
Cancel
Save