Browse Source

- added else branch to conditional actions

- implemented history for any object extending BaseClass (i.e. almost any)
- added distance() calculation method to base class
- Button "edit JSON" in Action Lists now hidden by default, can be enabled in plan properties

- fixed bugs:
    - updating json of DisplayText was not working properly
    - log output in Tile.isFreeFor was broken
lookup-tables
Stephan Richter 4 years ago
parent
commit
77166acf91
  1. 1
      .gitignore
  2. 4
      pom.xml
  3. 17
      resources/translations/Application.de.translation
  4. 2
      src/main/java/de/srsoftware/web4rail/Application.java
  5. 43
      src/main/java/de/srsoftware/web4rail/BaseClass.java
  6. 1
      src/main/java/de/srsoftware/web4rail/Constants.java
  7. 102
      src/main/java/de/srsoftware/web4rail/History.java
  8. 1
      src/main/java/de/srsoftware/web4rail/MaintnanceTask.java
  9. 9
      src/main/java/de/srsoftware/web4rail/Plan.java
  10. 6
      src/main/java/de/srsoftware/web4rail/Route.java
  11. 2
      src/main/java/de/srsoftware/web4rail/actions/Action.java
  12. 21
      src/main/java/de/srsoftware/web4rail/actions/ActionList.java
  13. 48
      src/main/java/de/srsoftware/web4rail/actions/ConditionalAction.java
  14. 8
      src/main/java/de/srsoftware/web4rail/actions/WaitForContact.java
  15. 3
      src/main/java/de/srsoftware/web4rail/conditions/ConditionList.java
  16. 2
      src/main/java/de/srsoftware/web4rail/tiles/Contact.java
  17. 4
      src/main/java/de/srsoftware/web4rail/tiles/Switch.java
  18. 8
      src/main/java/de/srsoftware/web4rail/tiles/Tile.java

1
.gitignore vendored

@ -5,6 +5,7 @@
*.cu *.cu
*.routes *.routes
*.trains *.trains
*.history
/backup /backup
/bin/ /bin/
/Debug/ /Debug/

4
pom.xml

@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>de.srsoftware</groupId> <groupId>de.srsoftware</groupId>
<artifactId>web4rail</artifactId> <artifactId>web4rail</artifactId>
<version>1.4.17</version> <version>1.4.18</version>
<name>Web4Rail</name> <name>Web4Rail</name>
<packaging>jar</packaging> <packaging>jar</packaging>
<description>Java Model Railway Control</description> <description>Java Model Railway Control</description>
@ -38,7 +38,7 @@
<dependency> <dependency>
<groupId>de.srsoftware</groupId> <groupId>de.srsoftware</groupId>
<artifactId>tools</artifactId> <artifactId>tools</artifactId>
<version>1.1.12</version> <version>1.1.15</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>

17
resources/translations/Application.de.translation

@ -7,6 +7,8 @@ Actions (On) : Aktionen (Ein)
Actions (Off) : Aktionen (Aus) Actions (Off) : Aktionen (Aus)
Actions and contacts : Aktionen und Kontakte Actions and contacts : Aktionen und Kontakte
Action type : Aktions-Typ Action type : Aktions-Typ
Actions in case conditions are fulfilled : Aktionen, wenn Bedingungen erfüllt sind
Actions in case conditions are <em>not</em> fulfilled : Aktionen, wenn Bedingungen <em>nicht</em> erfüllt sind
Actions will only fire, if all conditions are fullfilled. : Aktionen werden nur ausgeführt, wenn alle Bedingungen erfüllt sind. Actions will only fire, if all conditions are fullfilled. : Aktionen werden nur ausgeführt, wenn alle Bedingungen erfüllt sind.
ActivateRoute : Route aktivieren ActivateRoute : Route aktivieren
add : hinzufügen add : hinzufügen
@ -16,6 +18,7 @@ add action : Aktion hinzufügen
Add action to action list : Aktion zur Liste hinzufügen Add action to action list : Aktion zur Liste hinzufügen
add car : Waggon hinzufügen add car : Waggon hinzufügen
Add condition : Bedingung hinzufügen Add condition : Bedingung hinzufügen
Add entry : Eintrag hinzufügen
add locomotive : Lok hinzufügen add locomotive : Lok hinzufügen
add new aspect : neues Signalbild hinzufügen add new aspect : neues Signalbild hinzufügen
add new car : neuen Waggon anlegen add new car : neuen Waggon anlegen
@ -28,6 +31,7 @@ Address : Adresse
Add tag "{}" to train : Markierung "{}" zu Zug hinzufügen Add tag "{}" to train : Markierung "{}" zu Zug hinzufügen
Add tile : Kachel hinzufügen Add tile : Kachel hinzufügen
Add {} to destinations of train : {} zu den Zielen des Zugs hinzufügen Add {} to destinations of train : {} zu den Zielen des Zugs hinzufügen
Allow editing JSON of action lists : Bearbeiten von Action-Lists per JSON-Editor erlauben
analyze : analysieren analyze : analysieren
Analyze : analysieren Analyze : analysieren
Analyze may overwrite these routes! : Durch die Analyse können diese Fahrstraßen überschrieben werden! Analyze may overwrite these routes! : Durch die Analyse können diese Fahrstraßen überschrieben werden!
@ -109,6 +113,7 @@ Current location\: {} : Aufenthaltsort: {}
Current orientation : aktuelle Fahrtrichtung Current orientation : aktuelle Fahrtrichtung
Current velocity\: {} {} : Aktuelle Geschwindigkeit: {} {} Current velocity\: {} {} : Aktuelle Geschwindigkeit: {} {}
custom fields : benutzerdefinierte Felder custom fields : benutzerdefinierte Felder
Date/Time : Datum/Zeit
Decoder address : Decoder-Adresse Decoder address : Decoder-Adresse
decouple : Abkuppeln decouple : Abkuppeln
decoupler : decoupler decoupler : decoupler
@ -130,6 +135,7 @@ disable {} : {} deaktivieren
disabled routes : deaktivierte Fahrstraßen disabled routes : deaktivierte Fahrstraßen
DisableEnableBlock : Block (de)aktivieren DisableEnableBlock : Block (de)aktivieren
Display "{}" on {}. : „{}“ auf {} anzeigen. Display "{}" on {}. : „{}“ auf {} anzeigen.
Do you know, what you are doing? : Weißt du, was du da tust?
driven distance : zurückgelegte Strecke driven distance : zurückgelegte Strecke
Drop : Verwerfen Drop : Verwerfen
Drop brake times : Bremszeiten löschen Drop brake times : Bremszeiten löschen
@ -138,10 +144,12 @@ due after : fällig ab
1) Duration between 5 {} steps during brake process. : 1) Zeit zwischen 5 {}-Schritten beim Bremsvorgang. 1) Duration between 5 {} steps during brake process. : 1) Zeit zwischen 5 {}-Schritten beim Bremsvorgang.
EAST : Osten EAST : Osten
edit : bearbeiten edit : bearbeiten
edit JSON : JSON bearbeiten
Editable properties : veränderliche Eigenschaften Editable properties : veränderliche Eigenschaften
editable train properties : veränderliche Zug-Eigenschaften editable train properties : veränderliche Zug-Eigenschaften
Edit json : JSON bearbeiten Edit json : JSON bearbeiten
Effect : Effekt Effect : Effekt
else\: : falls nicht:
Emergency : Notfall Emergency : Notfall
empty train : leerer Zug empty train : leerer Zug
enable : aktivieren enable : aktivieren
@ -150,8 +158,9 @@ Engage {} : {} aktivieren
EngageDecoupler : Entkuppler aktivieren EngageDecoupler : Entkuppler aktivieren
Enter new name for plan : Neuen Namen für den Plan eingeben Enter new name for plan : Neuen Namen für den Plan eingeben
executed : ausgeführt executed : ausgeführt
executed "{}" after {} : "{}" nach {} ausgeführt
extended address : erweiterte Adresse extended address : erweiterte Adresse
export : exportieren Event : Ereignis
Faster ({} {}) : {} {} schneller Faster ({} {}) : {} {} schneller
Final speed after breaking, before halting : Endgeschwindigkeit nach Bremsvorgang, vor dem Anhalten Final speed after breaking, before halting : Endgeschwindigkeit nach Bremsvorgang, vor dem Anhalten
FinishRoute : Route abschließen FinishRoute : Route abschließen
@ -167,12 +176,12 @@ Function : Funktion
Hardware settings : Hardware-Einstellungen Hardware settings : Hardware-Einstellungen
Height : Höhe Height : Höhe
Help : Hilfe Help : Hilfe
History : Logbuch
Hold : an lassen Hold : an lassen
(id\: {}, length\: {}) : (Id: {}, Länge: {}) (id\: {}, length\: {}) : (Id: {}, Länge: {})
if ({}) : falls ({}) if ({}) : falls ({})
If car of train\: inspect car number : Falls Fahrzeug aus Zug: Untersuche Fahrzeug Nummer If car of train\: inspect car number : Falls Fahrzeug aus Zug: Untersuche Fahrzeug Nummer
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. 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. : Falls aktiviert, wird die Strecke anhand von Zug- und Kachel-Länge hinter dem Zug freigegeben, Falls deaktiviert wird die Strecke hinter dem Zug erst bei Abschluss der Route freigegeben.
Falls aktiviert, wird die Strecke anhand von Zug- und Kachel-Länge hinter dem Zug freigegeben, Falls deaktiviert wird die Strecke hinter dem Zug erst bei Abschluss der Route freigegeben.
internal contacts : interne Kontakte internal contacts : interne Kontakte
Interval : Intervall Interval : Intervall
inverted : invertiert inverted : invertiert
@ -215,6 +224,7 @@ 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 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 v<sub>min</sub> : Mindestanfahrspannung v<sub>min</sub> minimum starting voltage v<sub>min</sub> : Mindestanfahrspannung v<sub>min</sub>
Move tiles : Kacheln verschieben Move tiles : Kacheln verschieben
move up : nach oben schieben
name : Name name : Name
new car : neuer Waggon new car : neuer Waggon
new contact : neuer Kontakt new contact : neuer Kontakt
@ -366,6 +376,7 @@ Text to display on clients : Text, welcher auf den Clients angezeigt werden soll
Text to show on display : Text, welcher in der Anzeige dargestellt werden soll Text to show on display : Text, welcher in der Anzeige dargestellt werden soll
Tile(s) : Kachel(n) Tile(s) : Kachel(n)
Tile(s) moved. : Kachel(n) verschoben. Tile(s) moved. : Kachel(n) verschoben.
Timeout : maximale Wartezeit5
Toggle : umschalten Toggle : umschalten
toggle {} : {} umschalten toggle {} : {} umschalten
Toggle power : Stom umschalten Toggle power : Stom umschalten

2
src/main/java/de/srsoftware/web4rail/Application.java

@ -125,6 +125,8 @@ public class Application extends BaseClass{
return Condition.action(params,plan); return Condition.action(params,plan);
case REALM_CU: case REALM_CU:
return plan.controlUnit().process(params); return plan.controlUnit().process(params);
case REALM_HISTORY:
return History.action(params);
case REALM_LOCO: case REALM_LOCO:
return Locomotive.action(params,plan); return Locomotive.action(params,plan);
case REALM_MAINTENANCE: case REALM_MAINTENANCE:

43
src/main/java/de/srsoftware/web4rail/BaseClass.java

@ -18,8 +18,9 @@ import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import de.srsoftware.tools.translations.Translation;
import de.srsoftware.tools.Tag; import de.srsoftware.tools.Tag;
import de.srsoftware.tools.translations.Translation;
import de.srsoftware.web4rail.History.LogEntry;
import de.srsoftware.web4rail.Plan.Direction; import de.srsoftware.web4rail.Plan.Direction;
import de.srsoftware.web4rail.actions.Action; import de.srsoftware.web4rail.actions.Action;
import de.srsoftware.web4rail.conditions.Condition; import de.srsoftware.web4rail.conditions.Condition;
@ -308,6 +309,12 @@ public abstract class BaseClass implements Constants{
} }
} }
public Window addLogEntry(String text) {
History.assign(new History.LogEntry(text),this);
return properties();
}
public Button button(String text,Map<String,String> additionalProps) { public Button button(String text,Map<String,String> additionalProps) {
return new Button(text,props(additionalProps)); return new Button(text,props(additionalProps));
} }
@ -321,6 +328,25 @@ public abstract class BaseClass implements Constants{
return false; return false;
} }
public static String distance(long l) {
String unit = Plan.lengthUnit;
if (DEFAULT_LENGTH_UNIT.equals(unit)) {
if (l > 1_000_000) {
l/=1_000_000;
unit = t("km");
} else
if (l > 1_000) {
l/=1_000;
unit = t("m");
} else
if (l > 10) {
l/=10;
unit = t("cm");
}
}
return l+NBSP+unit;
}
public Form form(String id,List<Map.Entry<String, Tag>> elements) { public Form form(String id,List<Map.Entry<String, Tag>> elements) {
Form form = new Form(id); Form form = new Form(id);
@ -503,6 +529,21 @@ public abstract class BaseClass implements Constants{
new Button(t("Apply"),customForm).addTo(customForm).addTo(customFields); new Button(t("Apply"),customForm).addTo(customForm).addTo(customFields);
customFields.addTo(win); customFields.addTo(win);
Fieldset history = new Fieldset(t("History"));
Form form = new Form("add-history-entry");
new Input(REALM, REALM_HISTORY).hideIn(form);
new Input(ACTION, ACTION_ADD).hideIn(form);
new Input(ID,id()).hideIn(form);
new TextArea(NOTES).addTo(form);
new Button(t("Add entry"), form).addTo(form);
form.addTo(history);
table = new Table();
table.addHead(t("Date/Time"),t("Event"));
for (LogEntry entry : History.getFor(this)) table.addRow(new SimpleDateFormat("YYYY-dd-MM HH:mm").format(entry.date()),entry.getText());
table.addTo(history).addTo(win);
return win; return win;
} }

1
src/main/java/de/srsoftware/web4rail/Constants.java

@ -46,6 +46,7 @@ public interface Constants {
public static final String REALM_CONDITION = "condition"; public static final String REALM_CONDITION = "condition";
public static final String REALM_CONTACT = "contact"; public static final String REALM_CONTACT = "contact";
public static final String REALM_CU = "cu"; public static final String REALM_CU = "cu";
public static final String REALM_HISTORY = "history";
public static final String REALM_LOCO = "loco"; public static final String REALM_LOCO = "loco";
public static final String REALM_MAINTENANCE = "maintenance"; public static final String REALM_MAINTENANCE = "maintenance";
public static final String REALM_ROUTE = "route"; public static final String REALM_ROUTE = "route";

102
src/main/java/de/srsoftware/web4rail/History.java

@ -0,0 +1,102 @@
package de.srsoftware.web4rail;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Vector;
import org.json.JSONObject;
import de.srsoftware.web4rail.BaseClass.Id;
public class History {
private static HashMap<BaseClass.Id, Vector<LogEntry>> log = new HashMap<>();
static class LogEntry extends BaseClass {
private long timestamp;
private String text;
public LogEntry(String text) {
this.text = text;
timestamp = new Date().getTime();
}
public Date date() {
return new Date(timestamp);
}
public long getTime() {
return timestamp;
}
public String getText() {
return text;
}
};
public static LogEntry assign(LogEntry logEntry, BaseClass object) {
Id id = object.id();
Vector<LogEntry> list = log.get(id);
if (list == null) log.put(id, list = new Vector<>());
list.insertElementAt(logEntry,0);
return logEntry;
}
public static Vector<LogEntry> getFor(BaseClass object){
Vector<LogEntry> list = log.get(object.id());
return list != null ? list : new Vector<>();
}
public static Object action(HashMap<String, String> params) {
switch (params.get(Constants.ACTION)) {
case Constants.ACTION_ADD:
BaseClass object = BaseClass.get(Id.from(params));
return object != null ? object.addLogEntry(params.get(Constants.NOTES)) : BaseClass.t("Unknown object!");
}
return BaseClass.t("Unknown action: {}",params.get(Constants.ACTION));
}
public static void save(String filename) {
try {
FileWriter file = new FileWriter(filename, Constants.UTF8);
JSONObject json = new JSONObject();
log.entrySet().forEach(entry -> {
JSONObject list = new JSONObject();
entry.getValue().forEach(le -> list.put(le.timestamp+"", le.getText()));
json.put(entry.getKey().toString(), list);
});
json.write(file);
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void load(String filename) throws IOException {
BufferedReader file = new BufferedReader(new FileReader(filename, Constants.UTF8));
JSONObject json = new JSONObject(file.readLine());
file.close();
for (String id : json.keySet()) {
JSONObject o = json.getJSONObject(id);
Vector<LogEntry> entries = new Vector<>();
for (String time : o.keySet()) {
LogEntry le = new LogEntry(o.getString(time));
le.timestamp = Long.parseLong(time);
entries.add(le);
}
Collections.sort(entries, (a,b) -> Long.compare(b.timestamp, a.timestamp));
log.put(new Id(id), entries);
}
}
}

1
src/main/java/de/srsoftware/web4rail/MaintnanceTask.java

@ -84,6 +84,7 @@ public class MaintnanceTask extends BaseClass{
Block block = train.currentBlock(); Block block = train.currentBlock();
if (isSet(block)) plan.place(block); if (isSet(block)) plan.place(block);
} }
car.addLogEntry(t("executed \"{}\" after {}",name,BaseClass.distance(lastExecutionDist)));
return car.properties(); return car.properties();
} }
return t("parent is not a car!"); return t("parent is not a car!");

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

@ -157,12 +157,14 @@ public class Plan extends BaseClass{
private static final String FREE_BEHIND_TRAIN = "free_behind_train"; private static final String FREE_BEHIND_TRAIN = "free_behind_train";
private static final String RENAME = "rename"; private static final String RENAME = "rename";
private static final String SPEED_STEP = "speed_step"; private static final String SPEED_STEP = "speed_step";
private static final String ALLOW_JSON_EDIT = "allow_json_edit";
private String name = DEFAULT_NAME; private String name = DEFAULT_NAME;
private ControlUnit controlUnit = new ControlUnit(this); // the control unit, to which the plan is connected private ControlUnit controlUnit = new ControlUnit(this); // the control unit, to which the plan is connected
private Contact learningContact; private Contact learningContact;
private Configuration appConfig; private Configuration appConfig;
private LinkedList<EventListener> listeners = new LinkedList<>(); private LinkedList<EventListener> listeners = new LinkedList<>();
public static boolean allowJsonEdit = false;
/** /**
* creates a new plan, starts to send heart beats * creates a new plan, starts to send heart beats
@ -563,6 +565,9 @@ public class Plan extends BaseClass{
} catch (Exception e) { } catch (Exception e) {
LOG.warn("Was not able to establish connection to control unit!"); LOG.warn("Was not able to establish connection to control unit!");
} }
History.load(name+".history");
LoadCallback.fire(); LoadCallback.fire();
} }
@ -714,6 +719,7 @@ public class Plan extends BaseClass{
formInputs.add(t("Speed step"),new Input(SPEED_STEP, Train.defaultSpeedStep).attr("title", t("Speeds are always increadsed/decreased by this value"))); formInputs.add(t("Speed step"),new Input(SPEED_STEP, Train.defaultSpeedStep).attr("title", t("Speeds are always increadsed/decreased by this value")));
formInputs.add(t("Lower speed limit"),new Input(FINAL_SPEED, Train.defaultEndSpeed).attr("title", t("Final speed after breaking, before halting"))); formInputs.add(t("Lower speed limit"),new Input(FINAL_SPEED, Train.defaultEndSpeed).attr("title", t("Final speed after breaking, before halting")));
formInputs.add(t("Free tiles behind train"),new Checkbox(FREE_BEHIND_TRAIN, 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."), Route.freeBehindTrain)); formInputs.add(t("Free tiles behind train"),new Checkbox(FREE_BEHIND_TRAIN, 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."), Route.freeBehindTrain));
formInputs.add(t("Allow editing JSON of action lists"),new Checkbox(ALLOW_JSON_EDIT, t("Do you know, what you are doing?"), allowJsonEdit ));
postForm.add(relayProperties()); postForm.add(relayProperties());
postForm.add(routeProperties()); postForm.add(routeProperties());
@ -859,6 +865,8 @@ public class Plan extends BaseClass{
file.write(json().toString()); file.write(json().toString());
file.close(); file.close();
History.save(name+".history");
return t("Plan saved as \"{}\".",name); return t("Plan saved as \"{}\".",name);
} }
@ -1027,6 +1035,7 @@ public class Plan extends BaseClass{
if (params.containsKey(SPEED_UNIT)) speedUnit = params.get(SPEED_UNIT); if (params.containsKey(SPEED_UNIT)) speedUnit = params.get(SPEED_UNIT);
if (params.containsKey(SPEED_STEP)) Train.defaultSpeedStep = Integer.parseInt(params.get(SPEED_STEP)); if (params.containsKey(SPEED_STEP)) Train.defaultSpeedStep = Integer.parseInt(params.get(SPEED_STEP));
if (params.containsKey(FINAL_SPEED)) Train.defaultEndSpeed = Integer.parseInt(params.get(FINAL_SPEED)); if (params.containsKey(FINAL_SPEED)) Train.defaultEndSpeed = Integer.parseInt(params.get(FINAL_SPEED));
allowJsonEdit = "on".equalsIgnoreCase(params.get(ALLOW_JSON_EDIT));
Route.freeBehindTrain = "on".equalsIgnoreCase(params.get(FREE_BEHIND_TRAIN)); Route.freeBehindTrain = "on".equalsIgnoreCase(params.get(FREE_BEHIND_TRAIN));
return t("Plan updated."); return t("Plan updated.");

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

@ -348,7 +348,7 @@ public class Route extends BaseClass {
setupActions = new ActionList(this); setupActions = new ActionList(this);
triggeredActions.put(ROUTE_SETUP, setupActions); triggeredActions.put(ROUTE_SETUP, setupActions);
} }
setupActions.list().addTo(setup).addTo(list); setupActions.listAt(setup).addTo(list);
Tag start = new Tag("li").content(t("Start actions")+COL); Tag start = new Tag("li").content(t("Start actions")+COL);
ActionList startActions = triggeredActions.get(ROUTE_START); ActionList startActions = triggeredActions.get(ROUTE_START);
@ -356,7 +356,7 @@ public class Route extends BaseClass {
startActions = new ActionList(this); startActions = new ActionList(this);
triggeredActions.put(ROUTE_START, startActions); triggeredActions.put(ROUTE_START, startActions);
} }
startActions.list().addTo(start).addTo(list); startActions.listAt(start).addTo(list);
for (Contact c : contacts) { for (Contact c : contacts) {
Tag item = c.link("span", c).addTo(new Tag("li")).content(NBSP); Tag item = c.link("span", c).addTo(new Tag("li")).content(NBSP);
@ -365,7 +365,7 @@ public class Route extends BaseClass {
actions = new ActionList(this); actions = new ActionList(this);
triggeredActions.put(c.trigger(), actions); triggeredActions.put(c.trigger(), actions);
} }
actions.list().addTo(item).addTo(list); actions.listAt(item).addTo(list);
} }
list.addTo(win); list.addTo(win);
return win; return win;

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

@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory;
import de.srsoftware.tools.Tag; import de.srsoftware.tools.Tag;
import de.srsoftware.web4rail.BaseClass; import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.LoadCallback;
import de.srsoftware.web4rail.tags.Button; import de.srsoftware.web4rail.tags.Button;
import de.srsoftware.web4rail.tags.Fieldset; import de.srsoftware.web4rail.tags.Fieldset;
import de.srsoftware.web4rail.tags.Form; import de.srsoftware.web4rail.tags.Form;
@ -110,6 +111,7 @@ public abstract class Action extends BaseClass {
((ActionList)this).clear(); ((ActionList)this).clear();
} }
load(json); load(json);
LoadCallback.fire();
return context().properties(); return context().properties();
} }
Window win = new Window("json-import-export-"+id(), t("JSON code of {}",this)); Window win = new Window("json-import-export-"+id(), t("JSON code of {}",this));

21
src/main/java/de/srsoftware/web4rail/actions/ActionList.java

@ -123,23 +123,22 @@ public class ActionList extends Action implements Iterable<Action>{
return json; return json;
} }
public Tag list() { public <T extends Tag> T listAt(T parent) {
Tag span = new Tag("span"); button(parent.is("fieldset") ? t("add action") : "+", Map.of(ACTION, ACTION_ADD)).title(t("add action")).addTo(parent);
button(t("add action"), Map.of(ACTION, ACTION_ADD)).addTo(span); if (plan.allowJsonEdit) button(t("edit JSON"), Map.of(ACTION, ACTION_SAVE)).addTo(parent);
button(t("export"), Map.of(ACTION, ACTION_SAVE)).addTo(span);
if (!isEmpty()) { if (!isEmpty()) {
Tag list = new Tag("ol"); Tag list = new Tag("ol");
for (Action action : actions) { for (Action action : actions) {
Tag item = action.link("span",action).addTo(new Tag("li")).content(NBSP); Tag item = action.link("span",action).addTo(new Tag("li")).content(NBSP);
action.button("-", Map.of(ACTION,ACTION_DROP)).addTo(item); action.button("", Map.of(ACTION,ACTION_MOVE)).title(t("move up")).addTo(item);
action.button("", Map.of(ACTION,ACTION_MOVE)).addTo(item); action.button("-", Map.of(ACTION,ACTION_DROP)).title(t("delete")).addTo(item);
if (action instanceof ActionList) ((ActionList) action).list().addTo(item); if (action instanceof ActionList) ((ActionList) action).listAt(item);
item.addTo(list); item.addTo(list);
} }
list.addTo(span); list.addTo(parent);
} }
return span; return (T)parent;
} }
public Action load(JSONObject json) { public Action load(JSONObject json) {
@ -248,9 +247,7 @@ public class ActionList extends Action implements Iterable<Action>{
@Override @Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm,String...errors) { protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm,String...errors) {
Fieldset fieldset = new Fieldset(t("Actions")); preForm.add(listAt(new Fieldset(t("Actions")).clazz("actions")));
list().addTo(fieldset);
postForm.add(fieldset);
return super.properties(preForm, formInputs, postForm,errors); return super.properties(preForm, formInputs, postForm,errors);
} }

48
src/main/java/de/srsoftware/web4rail/actions/ConditionalAction.java

@ -2,10 +2,13 @@ package de.srsoftware.web4rail.actions;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.Vector;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONObject; import org.json.JSONObject;
import de.srsoftware.tools.Tag;
import de.srsoftware.web4rail.BaseClass; import de.srsoftware.web4rail.BaseClass;
import de.srsoftware.web4rail.conditions.Condition; import de.srsoftware.web4rail.conditions.Condition;
import de.srsoftware.web4rail.conditions.ConditionList; import de.srsoftware.web4rail.conditions.ConditionList;
@ -15,11 +18,14 @@ import de.srsoftware.web4rail.tags.Window;
public class ConditionalAction extends ActionList { public class ConditionalAction extends ActionList {
private static final String CONDITIONS = "conditions"; private static final String CONDITIONS = "conditions";
private static final String ELSE_ACTONS = "else_actions";
private ConditionList conditions = new ConditionList(); private ConditionList conditions = new ConditionList();
private ActionList elseActions;
public ConditionalAction(BaseClass parent) { public ConditionalAction(BaseClass parent) {
super(parent); super(parent);
conditions.parent(this); conditions.parent(this);
elseActions = new ActionList(parent);
} }
public boolean equals(ConditionalAction other) { public boolean equals(ConditionalAction other) {
@ -29,7 +35,7 @@ public class ConditionalAction extends ActionList {
@Override @Override
public boolean fire(Context context,Object cause) { public boolean fire(Context context,Object cause) {
for (Condition condition : conditions) { for (Condition condition : conditions) {
if (!condition.fulfilledBy(context)) return true; // wenn die Bedingung nicht erfüllt ist, ist das kein Fehler! if (!condition.fulfilledBy(context)) return elseActions.fire(context, cause);
} }
return super.fire(context.clone(),cause); // actions, that happen within the conditional action list must not modify the global context. return super.fire(context.clone(),cause); // actions, that happen within the conditional action list must not modify the global context.
} }
@ -48,13 +54,27 @@ public class ConditionalAction extends ActionList {
JSONArray conditions = new JSONArray(); JSONArray conditions = new JSONArray();
for (Condition condition : this.conditions) conditions.put(condition.json()); for (Condition condition : this.conditions) conditions.put(condition.json());
json.put(CONDITIONS, conditions); json.put(CONDITIONS, conditions);
if (!elseActions.isEmpty()) json.put(ELSE_ACTONS, elseActions.json());
return json; return json;
} }
@Override
public <T extends Tag> T listAt(T parent) {
T tag = super.listAt(parent);
if (!elseActions.isEmpty()) {
Tag div = new Tag("div").clazz("else");
new Tag("span").content(t("else:")+NBSP).addTo(div);
elseActions.listAt(div);
div.addTo(tag);
}
return tag;
}
@Override @Override
public Action load(JSONObject json) { public Action load(JSONObject json) {
super.load(json); super.load(json);
if (json.has(CONDITIONS)) { if (json.has(CONDITIONS)) {
conditions.clear();
for (Object o : json.getJSONArray(CONDITIONS)) { for (Object o : json.getJSONArray(CONDITIONS)) {
if (o instanceof JSONObject) { if (o instanceof JSONObject) {
JSONObject j = (JSONObject) o; JSONObject j = (JSONObject) o;
@ -66,13 +86,37 @@ public class ConditionalAction extends ActionList {
} }
} }
} }
if (json.has(ELSE_ACTONS)) elseActions.load(json.getJSONObject(ELSE_ACTONS));
return this; return this;
} }
@Override @Override
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm,String...errors) { protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm,String...errors) {
preForm.add(conditions.list()); preForm.add(conditions.list());
return super.properties(preForm, formInputs, postForm,errors); Window win = super.properties(preForm, formInputs, postForm,errors);
Optional<Fieldset> actionFieldSet = win.children()
.stream()
.filter(tag -> tag instanceof Fieldset)
.map(tag -> (Fieldset)tag)
.filter(fs -> "actions".equals(fs.get("class")))
.findFirst();
if (actionFieldSet.isPresent()) {
Vector<Tag> children = actionFieldSet.get().children();
children.insertElementAt(new Tag("h3").content(t("Actions in case conditions are fulfilled")),1);
LOG.debug("children: "+children);
Optional<Tag> elseTag = children.stream().filter(tag -> "else".equals(tag.get("class"))).findFirst();
if (elseTag.isPresent()) {
children = elseTag.get().children();
children.remove(0);
children.insertElementAt(new Tag("h3").content(t("Actions in case conditions are <em>not</em> fulfilled")),0);
} else {
children.add(new Tag("h3").content(t("Actions in case conditions are <em>not</em> fulfilled")));
elseActions.listAt(actionFieldSet.get());
}
}
return win;
} }

8
src/main/java/de/srsoftware/web4rail/actions/WaitForContact.java

@ -69,14 +69,14 @@ public class WaitForContact extends ActionList {
} }
@Override @Override
public Tag list() { public <T extends Tag> T listAt(T parent) {
Tag list = super.list(); T list = super.listAt(parent);
for (Tag child : list.children()) { for (Tag child : list.children()) {
if (child.is("ol")) { if (child.is("ol")) {
break; break;
} }
} }
timeoutActions.list().addTo(new Tag("span").content(t("On timeout (after {} ms)",timeout)+":")).addTo(list); timeoutActions.listAt(new Tag("span").content(t("On timeout (after {} ms)",timeout)+":")).addTo(list);
return list; return list;
} }
@ -103,7 +103,7 @@ public class WaitForContact extends ActionList {
Fieldset fieldset = new Fieldset(t("Actions on timeout")); Fieldset fieldset = new Fieldset(t("Actions on timeout"));
fieldset.id("actions"); fieldset.id("actions");
timeoutActions.list().addTo(fieldset); timeoutActions.listAt(fieldset);
postForm.add(fieldset); postForm.add(fieldset);
return super.properties(preForm, formInputs, postForm,errors); return super.properties(preForm, formInputs, postForm,errors);

3
src/main/java/de/srsoftware/web4rail/conditions/ConditionList.java

@ -31,6 +31,9 @@ public class ConditionList extends Condition implements Iterable<Condition>{
this.conditions.addAll(conditions.conditions); this.conditions.addAll(conditions.conditions);
} }
public void clear() {
conditions.clear();
}
public boolean fulfilledBy(Context context) { public boolean fulfilledBy(Context context) {
for (Condition condition : conditions) { for (Condition condition : conditions) {

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

@ -189,7 +189,7 @@ public class Contact extends Tile{
formInputs.add(t("Address"),span); formInputs.add(t("Address"),span);
Fieldset fieldset = new Fieldset(t("Actions")).id("props-actions"); Fieldset fieldset = new Fieldset(t("Actions")).id("props-actions");
actions.list().addTo(fieldset); actions.listAt(fieldset);
postForm.add(fieldset); postForm.add(fieldset);
return super.properties(preForm, formInputs, postForm,errors); return super.properties(preForm, formInputs, postForm,errors);
} }

4
src/main/java/de/srsoftware/web4rail/tiles/Switch.java

@ -129,11 +129,11 @@ public class Switch extends Tile{
protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm,String...errors) { protected Window properties(List<Fieldset> preForm, FormInput formInputs, List<Fieldset> postForm,String...errors) {
Fieldset fieldset = new Fieldset(t("Actions (On)")); Fieldset fieldset = new Fieldset(t("Actions (On)"));
fieldset.id("actionsOn"); fieldset.id("actionsOn");
actionsOn.list().addTo(fieldset); actionsOn.listAt(fieldset);
postForm.add(fieldset); postForm.add(fieldset);
fieldset = new Fieldset(t("Actions (Off)")); fieldset = new Fieldset(t("Actions (Off)"));
fieldset.id("actionsOff"); fieldset.id("actionsOff");
actionsOff.list().addTo(fieldset); actionsOff.listAt(fieldset);
postForm.add(fieldset); postForm.add(fieldset);
return super.properties(preForm, formInputs, postForm,errors); return super.properties(preForm, formInputs, postForm,errors);
} }

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

@ -149,18 +149,18 @@ public abstract class Tile extends BaseClass implements Comparable<Tile> {
Train train = newTrain.train(); Train train = newTrain.train();
if (isSet(reservingTrain) && reservingTrain != train) { if (isSet(reservingTrain) && reservingTrain != train) {
LOG.debug("{} is reserved for {}",reservingTrain); LOG.debug("{} is reserved for {}",this,reservingTrain);
return false; // nicht in reservierten Block einfahren! return false; // nicht in reservierten Block einfahren!
} }
if (isSet(lockingTrain) && lockingTrain != train) { if (isSet(lockingTrain) && lockingTrain != train) {
LOG.debug("{} is locked for {}",lockingTrain); LOG.debug("{} is locked for {}",this,lockingTrain);
return false; // nicht in reservierten Block einfahren! return false; // nicht in reservierten Block einfahren!
} }
if (isSet(occupyingTrain) && occupyingTrain != train) { if (isSet(occupyingTrain) && occupyingTrain != train) {
LOG.debug("{} is occupied by {}",occupyingTrain); LOG.debug("{} is occupied by {}",this,occupyingTrain);
return train.isShunting(); // nur in belegte Blöcke einfahren, wenn Rangiermodus aktiv! return isSet(train) && train.isShunting(); // nur in belegte Blöcke einfahren, wenn Rangiermodus aktiv!
} }
return true; return true;

Loading…
Cancel
Save