# HG changeset patch # User gernotbelger # Date 1516357422 -3600 # Node ID 28df64078f279b595aed33f133e4336465fab5e2 # Parent 7bbfb24e6eec67d3163b802cb094ae93ae41ba43# Parent 0862ea5d66baf60e7eee496d130a35157cc9ec12 Merge with 0862ea5d66baf60e7eee496d130a35157cc9ec12 diff -r 0862ea5d66ba -r 28df64078f27 artifacts/TODO --- a/artifacts/TODO Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/TODO Fri Jan 19 11:23:42 2018 +0100 @@ -1,1 +1,1 @@ -- Validation of the input values of an incoming feed() call +- Validation of the input values of an incoming feed() call \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/artifacts/manualpoints.xml --- a/artifacts/doc/conf/artifacts/manualpoints.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/artifacts/manualpoints.xml Fri Jan 19 11:23:42 2018 +0100 @@ -35,6 +35,8 @@ + + diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/artifacts/sinfo.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/doc/conf/artifacts/sinfo.xml Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/backend-db.xml --- a/artifacts/doc/conf/backend-db.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/backend-db.xml Fri Jan 19 11:23:42 2018 +0100 @@ -5,7 +5,7 @@ d4e org.hibernate.dialect.PostgreSQLDialect org.postgresql.Driver - jdbc:postgresql://localhost:5432/d4e + jdbc:postgresql://localhost:63333/d4e select 1 from rivers 30000 diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/conf.xml --- a/artifacts/doc/conf/conf.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/conf.xml Fri Jan 19 11:23:42 2018 +0100 @@ -22,6 +22,8 @@ + + ]> YOUR_SECRET @@ -168,6 +170,12 @@ org.dive4elements.artifactdatabase.DefaultArtifactFactory + + + org.dive4elements.artifactdatabase.DefaultArtifactFactory + org.dive4elements.artifactdatabase.DefaultUserFactory @@ -299,6 +307,8 @@ &gaugedischargecurve-artifact; &sedimentload-artifact; &sedimentload-ls-artifact; + + &sinfo_artifact; &modules; diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/generators/generators.xml --- a/artifacts/doc/conf/generators/generators.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/generators/generators.xml Fri Jan 19 11:23:42 2018 +0100 @@ -58,5 +58,10 @@ + + + + + diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml --- a/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/generators/longitudinal-diagram-defaults.xml Fri Jan 19 11:23:42 2018 +0100 @@ -14,8 +14,8 @@ - + + @@ -42,4 +42,7 @@ - + + + + \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/generators/longitudinal-diagrams.xml --- a/artifacts/doc/conf/generators/longitudinal-diagrams.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/generators/longitudinal-diagrams.xml Fri Jan 19 11:23:42 2018 +0100 @@ -87,5 +87,20 @@ - + + + + &longitudinal-defaults; + <processor class="org.dive4elements.river.exports.process.ManualPointsProcessor" + axis="FlowDepth"/> + <subtitle key="chart.w_differences.subtitle" default="-"> + <arg expr="artifact.river"/> + </subtitle> + </output-generator> +</longitudinal-diagrams> \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/jasper/FIXME.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/doc/conf/jasper/FIXME.txt Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,6 @@ +Awful: +- source files together with compiled files in one directory +- source files part of 'conf', but user will probably never be able to conf them +- compiled files checked-in into SCM +- compilation process not part of maven (not even part of project at all) +- we have different jasper reports for different languages; instead introduce variables and give i10n strings as report variables \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/jasper/templates/sinfo.flowdepth.jrxml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/doc/conf/jasper/templates/sinfo.flowdepth.jrxml Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,215 @@ +<?xml version="1.0" encoding="UTF-8"?> +<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="flysreport" language="groovy" pageWidth="595" pageHeight="842" columnWidth="515" leftMargin="60" rightMargin="20" topMargin="20" bottomMargin="20"> + <property name="ireport.zoom" value="1.0"/> + <property name="ireport.x" value="0"/> + <property name="ireport.y" value="0"/> + + <field name="meta:version" class="java.lang.String"/> + <field name="meta:user" class="java.lang.String"/> + <field name="meta:date" class="java.lang.String"/> + <field name="meta:river" class="java.lang.String"/> + <field name="meta:range" class="java.lang.String"/> + + <field name="data:0" class="java.lang.String"/> + <field name="data:1" class="java.lang.String"/> + <field name="data:2" class="java.lang.String"/> + <field name="data:3" class="java.lang.String"/> + <field name="data:4" class="java.lang.String"/> + <field name="data:5" class="java.lang.String"/> +<!-- + <field name="data:6" class="java.lang.String"/> + <field name="data:7" class="java.lang.String"/> + <field name="data:8" class="java.lang.String"/> + <field name="data:9" class="java.lang.String"/> + <field name="data:10" class="java.lang.String"/> + <field name="data:11" class="java.lang.String"/> +--> + + <background> + <band splitType="Stretch"/> + </background> + <title> + <band height="182" splitType="Stretch"> + <staticText> + <reportElement x="0" y="1" width="165" height="30"/> + <textElement> + <font size="18"/> + </textElement> + <text><![CDATA[Ergebnisausgabe]]></text> + </staticText> + <!-- + <textField> + <reportElement x="165" y="0" width="350" height="31"/> + <textElement> + <font size="18"/> + </textElement> + <textFieldExpression><![CDATA[$F{meta:version}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="165" y="0" width="350" height="31"/> + <textElement> + <font size="18"/> + </textElement> + <textFieldExpression><![CDATA[$F{meta:user}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="165" y="0" width="350" height="31"/> + <textElement> + <font size="18"/> + </textElement> + <textFieldExpression><![CDATA[$F{river}]]></textFieldExpression> + </textField> + <textField> + <reportElement x="0" y="31" width="515" height="26"/> + <textElement> + <font size="14"/> + </textElement> + <textFieldExpression><![CDATA[$F{calculation}]]></textFieldExpression> + </textField> + --> + + <staticText> + <reportElement x="0" y="70" width="123" height="20"/> + <textElement/> + <text><![CDATA[FLYS-Version:]]></text> + </staticText> + <textField> + <reportElement x="123" y="70" width="392" height="20"/> + <textElement/> + <textFieldExpression><![CDATA[$F{meta:version}]]></textFieldExpression> + </textField> + + <staticText> + <reportElement x="0" y="90" width="123" height="20"/> + <textElement/> + <text><![CDATA[Bearbeiter:]]></text> + </staticText> + <textField> + <reportElement x="123" y="90" width="392" height="20"/> + <textElement/> + <textFieldExpression><![CDATA[$F{meta:user}]]></textFieldExpression> + </textField> + + <staticText> + <reportElement x="0" y="110" width="123" height="20"/> + <textElement/> + <text><![CDATA[Datum der Erstellung:]]></text> + </staticText> + <textField> + <reportElement x="123" y="110" width="392" height="20"/> + <textElement/> + <textFieldExpression><![CDATA[$F{meta:date}]]></textFieldExpression> + </textField> + + <staticText> + <reportElement x="0" y="130" width="123" height="20"/> + <textElement/> + <text><![CDATA[Gewässer:]]></text> + </staticText> + <textField> + <reportElement x="123" y="130" width="392" height="20"/> + <textElement/> + <textFieldExpression><![CDATA[$F{meta:river}]]></textFieldExpression> + </textField> + + <staticText> + <reportElement x="0" y="150" width="123" height="20"/> + <textElement/> + <text><![CDATA[Bereich:]]></text> + </staticText> + <textField> + <reportElement x="123" y="150" width="392" height="20"/> + <textElement/> + <textFieldExpression><![CDATA[$F{meta:range}]]></textFieldExpression> + </textField> + </band> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/log4j.properties --- a/artifacts/doc/conf/log4j.properties Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/log4j.properties Fri Jan 19 11:23:42 2018 +0100 @@ -4,7 +4,7 @@ log4j.category.org.hibernate=WARN log4j.category.net.sf.ehcache=WARN log4j.category.org.eclipse=WARN -log4j.category.org.restlet=INFO +log4j.category.org.restlet=WARN ########## APPENDER SETTINGS @@ -12,10 +12,7 @@ log4j.appender.FLYS.layout.ConversionPattern=%d{HH:mm:ss} [%t] %-5p %c{1} - %m%n -log4j.appender.FLYS=org.apache.log4j.RollingFileAppender -log4j.appender.FLYS.File=/var/log/d4e-river/d4e-server.log -log4j.appender.FLYS.MaxFileSize=5000KB -log4j.appender.FLYS.MaxBackupIndex=1 +log4j.appender.FLYS=org.apache.log4j.ConsoleAppender log4j.logger.org.dive4elements.artifactdatabase.rest.Standalone=INFO, START log4j.appender.START=org.apache.log4j.ConsoleAppender diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/meta-data.xml --- a/artifacts/doc/conf/meta-data.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/meta-data.xml Fri Jan 19 11:23:42 2018 +0100 @@ -242,6 +242,19 @@ + + S-INFO + + + + + + + + + + + diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/modules.xml --- a/artifacts/doc/conf/modules.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/modules.xml Fri Jan 19 11:23:42 2018 +0100 @@ -3,6 +3,9 @@ + + + @@ -15,5 +18,4 @@ - - + \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/seddb-db.xml --- a/artifacts/doc/conf/seddb-db.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/seddb-db.xml Fri Jan 19 11:23:42 2018 +0100 @@ -5,7 +5,7 @@ seddb org.hibernate.dialect.PostgreSQLDialect org.postgresql.Driver - jdbc:postgresql://localhost:5432/seddb + jdbc:postgresql://localhost:63333/seddb select 1 from gewaesser 30000 + + + - - + \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/themes/default.xml --- a/artifacts/doc/conf/themes/default.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/themes/default.xml Fri Jan 19 11:23:42 2018 +0100 @@ -2872,4 +2872,16 @@ + + + + + + + + + + + diff -r 0862ea5d66ba -r 28df64078f27 artifacts/doc/conf/themes/second.xml --- a/artifacts/doc/conf/themes/second.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/doc/conf/themes/second.xml Fri Jan 19 11:23:42 2018 +0100 @@ -2869,4 +2869,15 @@ - + + + + + + + + + + + \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/model/DataFacet.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/DataFacet.java Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/DataFacet.java Fri Jan 19 11:23:42 2018 +0100 @@ -104,12 +104,14 @@ */ @Override public Facet deepCopy() { + // FIXME: why not use the full constructor instead? would also fix the next problem DataFacet copy = new DataFacet(); + // FIXME: usage of internal knowledge of parent class... + // Either the set method should be correctly overwritten, or implement a correct copy-constructor! copy.set(this); copy.type = type; copy.hash = hash; copy.stateId = stateId; return copy; } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/FacetTypes.java Fri Jan 19 11:23:42 2018 +0100 @@ -189,6 +189,8 @@ SQF("sq_relation_f"), HD("historical_discharge"), HDWQ("historical_discharge_wq"); + // FIXME: do we need this? and why? + // SFD("sinfo_flow_depth"); private String chartTypeString; diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/resources/Resources.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/resources/Resources.java Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/resources/Resources.java Fri Jan 19 11:23:42 2018 +0100 @@ -124,18 +124,18 @@ * @return a translated string. */ public static String getMsg( - CallMeta meta, - String key, - String def, - Object[] args) + CallMeta meta, + String key, + String def, + Object... args) { - String template = getMsg(meta, key, (String)null); - - if (template == null) { - return def; - } - - return format(meta, template, args); + String template = getMsg(meta, key, (String)null); + + if (template == null) { + return def; + } + + return format(meta, template, args); } public static String format( diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/CalculationSelectSinfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/CalculationSelectSinfo.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,78 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.sinfo; + +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.dive4elements.artifacts.Artifact; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.artifacts.CallMeta; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.states.DefaultState; +import org.w3c.dom.Element; + +/** + * @author Gernot Belger + */ +public class CalculationSelectSinfo extends DefaultState { + + private static final long serialVersionUID = 1L; + + /** The log that is used in this class. */ + private static Logger log = Logger.getLogger(CalculationSelectSinfo.class); + + public CalculationSelectSinfo() { + } + + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + final CallMeta meta = context.getMeta(); + + final Collection calcs = new ArrayList<>(SinfoCalcMode.values().length); + + for (final SinfoCalcMode calcMode : SinfoCalcMode.values()) { + final String calc = calcMode.name(); + + final String label = Resources.getMsg(meta, calc, calc); + + final Element element = createItem( + cr, new String[] { + label, + calc + }); + calcs.add(element); + } + + return calcs.toArray(new Element[calcs.size()]); + } + + @Override + public boolean validate(Artifact artifact) + throws IllegalArgumentException + { + log.debug("CalculationSelect.validate"); + + final SINFOArtifact sinfo = (SINFOArtifact) artifact; + /* throws an exception if calculation mode is invalid */ + sinfo.getCalculationMode(); + return true; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SINFOArtifact.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SINFOArtifact.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,73 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.sinfo; + +import org.apache.commons.lang.StringUtils; +import org.dive4elements.river.artifacts.D4EArtifact; + +/** + * The default MINFO artifact. + * + * @author Gernot Belger + */ +public class SINFOArtifact +extends D4EArtifact +{ + /** Error message that is thrown if no mode has been chosen. */ + private static final String ERROR_NO_CALCULATION_MODE = + "error_feed_no_calculation_mode"; + + /** Error message that is thrown if an invalid calculation mode has been + * chosen. */ + private static final String ERROR_INVALID_CALCULATION_MODE = + "error_feed_invalid_calculation_mode"; + + + /** The name of the artifact. */ + private static final String ARTIFACT_NAME = "sinfo"; + + private static final String FIELD_FIVER = "river"; + + private static final String FIELD_MODE = "calculation_mode"; + + /** + * Default constructor, because it's serializable. + */ + public SINFOArtifact() { + } + + /** + * Returns the name of the concrete artifact. + * + * @return the name of the concrete artifact. + */ + @Override + public String getName() { + return ARTIFACT_NAME; + } + + public SinfoCalcMode getCalculationMode() { + + final String calc = getDataAsString(FIELD_MODE); + if (calc == null) { + throw new IllegalArgumentException(ERROR_NO_CALCULATION_MODE); + } + + try { + return SinfoCalcMode.valueOf(StringUtils.trimToEmpty(calc).toLowerCase()); + } catch (Exception e) { + throw new IllegalArgumentException(ERROR_INVALID_CALCULATION_MODE, e); + } + } + + public String getRiver() { + return getDataAsString(FIELD_FIVER); + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SinfoCalcMode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/SinfoCalcMode.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,20 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.sinfo; + +public enum SinfoCalcMode{ + sinfo_calc_flow_depth, + sinfo_calc_flow_depth_development, + sinfo_calc_flow_depth_minmax, + sinfo_calc_grounding, + sinfo_calc_transport_bodies_heights, + sinfo_calc_infrastructures_inundation_duration +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthAccess.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthAccess.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,88 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import org.dive4elements.river.artifacts.access.RangeAccess; +import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; +import org.dive4elements.river.artifacts.sinfo.SinfoCalcMode; +import org.dive4elements.river.backend.utils.StringUtil; + +/** + * Access to the flow depth calculation type specific SInfo artifact data. + * REMARK: this class is NOT intended to be hold in the results (or anywhere else), in order to avoid a permanent reference to the artifact instance. + * Hence we do NOT cache any data. + * + * @author Gernot Belger + */ +public class FlowDepthAccess +extends RangeAccess +{ + public static class DifferencesPair + { + private final String wstId; + private final String soundingId; + + public DifferencesPair( final String wstId, final String soundingId ) { + this.wstId = wstId; + this.soundingId = soundingId; + } + + public String getWstId() { + return this.wstId; + } + + public String getSoundingId() { + return this.soundingId; + } + } + + private static final String FIELD_USE_TKH = "use_transport_bodies"; //$NON-NLS-1$ + + public FlowDepthAccess(final SINFOArtifact artifact) { + super(artifact); + + /* assert calculation mode */ + final SinfoCalcMode calculationMode = artifact.getCalculationMode(); + assert(calculationMode == SinfoCalcMode.sinfo_calc_flow_depth); + } + + public boolean isUseTransportBodies() { + final Boolean useTkh = artifact.getDataAsBoolean( FIELD_USE_TKH ); + return useTkh == null ? false : useTkh; + } + + public Collection getDifferencePairs() { + + final Collection diffPairs = new ArrayList<>(); + + final String diffids = super.getString("diffids"); + if( diffids == null ) + { + // Should never happen as this is handled by the ui + return Collections.emptyList(); + } + + // FIXME: this way of parsing the datacage-ids is repeated all over flys! + final String datas[] = diffids.split("#"); + for(int i = 0; i < datas.length; i+=2) { + final String leftId = StringUtil.unbracket( datas[i] ); + final String rightId = StringUtil.unbracket( datas[i+1] ); + + diffPairs.add(new DifferencesPair(leftId, rightId)); + } + + return Collections.unmodifiableCollection(diffPairs); + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculation.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,152 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import java.util.Collection; +import java.util.List; + +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.BedHeightsArtifact; +import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.artifacts.model.CalculationResult; +import org.dive4elements.river.artifacts.model.LocationProvider; +import org.dive4elements.river.artifacts.model.WKms; +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; +import org.dive4elements.river.artifacts.sinfo.flowdepth.FlowDepthAccess.DifferencesPair; +import org.dive4elements.river.artifacts.states.WDifferencesState; +import org.dive4elements.river.model.BedHeight; +import org.dive4elements.river.model.Gauge; +import org.dive4elements.river.model.River; +import org.dive4elements.river.utils.GaugeIndex; +import org.dive4elements.river.utils.RiverUtils; + +class FlowDepthCalculation { + + private static final String CSV_NOT_IN_GAUGE_RANGE = "export.waterlevel.csv.not.in.gauge.range"; + + private CallContext context; + + public FlowDepthCalculation( final CallContext context ) { + this.context = context; + } + + public CalculationResult calculate(final SINFOArtifact sinfo) { + + /* access input data */ + final FlowDepthAccess access = new FlowDepthAccess(sinfo); + final River river = access.getRiver(); + + final Collection diffPairs = access.getDifferencePairs(); + + final double from = access.getFrom(); + final double to = access.getTo(); + + final boolean useTkh = access.isUseTransportBodies(); + + /* calculate results for each diff pair */ + final Calculation problems = new Calculation(); + + final List gauges = river.determineGauges(from, to); + final GaugeIndex gaugeIndex = new GaugeIndex(gauges); + + final FlowDepthCalculationResults results = new FlowDepthCalculationResults(river, from, to, useTkh); + + for (final DifferencesPair diffPair : diffPairs) { + final FlowDepthCalculationResult result = calculateResult( river, from, to, diffPair, problems, gaugeIndex ); + if( result != null ) + results.addResult(result); + } + + return new CalculationResult(results,problems); + } + + private FlowDepthCalculationResult calculateResult(final River river, final double from, final double to, final DifferencesPair diffPair, final Calculation problems, final GaugeIndex gaugeIndex) { + + /* access real input data from database */ + final String soundingId = diffPair.getSoundingId(); + final String wstId = diffPair.getWstId(); + + final BedHeight bedHeight = loadBedHeight( soundingId, from, to ); + final WKms wstKms = new WDifferencesState().getWKms(wstId, context, from, to); + if( bedHeight == null || wstKms == null ) + return null; + + final FlowDepthCalculationResult resultData = new FlowDepthCalculationResult(wstKms.getName(), bedHeight.getDescription()); + + final String notinrange = Resources.getMsg(context.getMeta(), CSV_NOT_IN_GAUGE_RANGE, CSV_NOT_IN_GAUGE_RANGE); + + // TODO: unklarheiten + // 'idealerweise alle 100m' was heisst das? kann doch nur durch datenverfügbarkeit bestimmt werden + // wie mit unterschiedlichen Ranges umgehen? Schnitt bilden? Fehlermeldung? ...? + // wie interpolieren? wst interpolieren? peilung interpolieren? + + // FIXME: für die Berechnung der TKH sind weitere 'in FLYS vorliegende' Daten notwendig. + // aktuell unklar ob das durch andere Barten berechnete Werte oder Basisdaten sind + // TODO: check Vergleiche BArt 'Transportkörperhöhen' + + // TODO: Berechnung der Transportkörperhöhen + // - woher kommen die zusätzlichen eingangsdaten? sind das fixe daten pro gewässer? --> falls ja, warum nicht einmal berechnen und in db ablegen? + + final String bedHeightLabel = bedHeight.getDescription(); + final String wstLabel = wstKms.getName(); + + for (int i = 0; i < wstKms.size(); i++) { + + final double km = wstKms.getKm(i); + final double wst = wstKms.getW(i); + // FIXME: interpolate from bedheights? + final double meanBedHeight = 79.32; + + final double flowDepth = wst - meanBedHeight; + + final double tkh = 0; + final double flowDepthTkh = flowDepth - tkh; + + // FIXME: discharge not available for all wst? or any? + final double discharge = 0.0; + + // REMARK: access the location once only during calculation + final String location = LocationProvider.getLocation(river.getName(), km); + + // REMARK: access the gauge once only during calculation + final Gauge gauge = gaugeIndex.findGauge(km); + final String gaugeLabel = gauge == null ? notinrange : gauge.getName(); + + resultData.addRow( km, flowDepth, flowDepthTkh, tkh, wst, discharge, wstLabel, gaugeLabel, meanBedHeight, bedHeightLabel, location ); + } + + return resultData; + } + + private BedHeight loadBedHeight(final String soundingId, final double from, final double to) { + + // FIXME: absolutely unbelievable.... + // The way how bed-heights (and other data too) is accessed is different for nearly ever calculation-type throughout flys. + // The knowledge on how to parse the datacage-ids is spread thorugh the complete code-base... + + // We use here the way on how bed-heights are accessed by the BedDifferenceAccess/BedDifferenceCalculation, but this is plain random + final String[] parts = soundingId.split(";"); + + final BedHeightsArtifact artifact = (BedHeightsArtifact) RiverUtils.getArtifact(parts[0], context); + + final Integer bedheightId = artifact.getDataAsInteger("height_id"); + // FIXME: this only works with type 'single'; unclear on how to distinguish from epoch data (or whatever the other type means) + // Luckily, the requirement is to only access 'single' data here. + // final String bedheightType = artifact.getDataAsString("type"); + + // FIXME: BedDifferences uses this, but we also need the metadata of the BedHeight + // FIXME: second absolutely awful thing: BedHeight is a hibernate binding class, accessing the database via hibernate stuff + // BedHeightFactory uses its own (direct) way of accessing the data, with its own implemented data classes. + //return BedHeightFactory.getHeight(bedheightType, bedheightId, from, to); + + return BedHeight.getBedHeightById(bedheightId); + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResult.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,68 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; + +import gnu.trove.TDoubleArrayList; + +/** + * Contains the results of a {@link FlowDepthCalculation}. + * + * @author Gernot Belger + */ +class FlowDepthCalculationResult +implements Serializable { + + private static final long serialVersionUID = 1L; + + private final Collection rows = new ArrayList<>(); + + private final String wstLabel; + + private final String soundingLabel; + + public FlowDepthCalculationResult(final String wstLabel, final String soundingLabel) { + this.wstLabel = wstLabel; + this.soundingLabel = soundingLabel; + } + + public void addRow(double station, double flowDepth, double flowDepthWithTkh, double tkh, double waterlevel, double discharge, String waterlevelLabel, String gauge, double meanBedHeight, String sondageLabel, String location) { + rows.add(new FlowDepthRow(station, flowDepth, flowDepthWithTkh, tkh, waterlevel, discharge, waterlevelLabel, gauge, meanBedHeight, sondageLabel, location)); + } + + public String getWstLabel() { + return this.wstLabel; + } + + public String getSoundingLabel() { + return this.soundingLabel; + } + + public Collection getRows() { + return Collections.unmodifiableCollection( rows ); + } + + public double[][] getFlowDepthPoints() { + + TDoubleArrayList xPoints = new TDoubleArrayList(rows.size()); + TDoubleArrayList yPoints = new TDoubleArrayList(rows.size()); + + for (FlowDepthRow row : rows) { + xPoints.add(row.getStation()); + yPoints.add(row.getFlowDepth()); + } + + return new double[][] { xPoints.toNativeArray(), yPoints.toNativeArray() }; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthCalculationResults.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,63 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import org.dive4elements.river.model.River; + +/** + * @author Gernot Belger + * + */ +public class FlowDepthCalculationResults{ + private final List results = new ArrayList<>(); + + private final River river; + + private final double from; + + private final double to; + + private final boolean useTkh; + + public FlowDepthCalculationResults(final River river, final double from, final double to, final boolean useTkh) { + this.river = river; + this.from = from; + this.to = to; + this.useTkh = useTkh; + } + + public River getRiver() { + return this.river; + } + + public double getFrom() { + return this.from; + } + + public double getTo() { + return this.to; + } + + public boolean isUseTkh() { + return this.useTkh; + } + + void addResult(final FlowDepthCalculationResult result) { + results.add(result); + } + + public List getResults() { + return Collections.unmodifiableList(results); + } +} diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthExporter.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,449 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.NumberFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.dive4elements.artifacts.CallMeta; +import org.dive4elements.artifacts.common.utils.Config; +import org.dive4elements.river.artifacts.model.CalculationResult; +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.sinfo.util.MetaAndTableJRDataSource; +import org.dive4elements.river.exports.AbstractExporter; +import org.dive4elements.river.model.River; +import org.dive4elements.river.utils.Formatter; + +import au.com.bytecode.opencsv.CSVWriter; +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JasperExportManager; +import net.sf.jasperreports.engine.JasperFillManager; +import net.sf.jasperreports.engine.JasperPrint; + +/** + * Generates different output formats (csv, pdf) of data that resulted from a flow depths computation. + * + * @author Ingo Weinzierl + * @author Gernot Belger + */ +// REMARK: must be public because its registered in generators.xml +public class FlowDepthExporter extends AbstractExporter { + + /** The log used in this exporter.*/ + private static Logger log = Logger.getLogger(FlowDepthExporter.class); + + private static final String CSV_KM_HEADER = "sinfo.export.flow_depth.csv.header.km"; + private static final String CSV_FLOWDEPTH_HEADER = "sinfo.export.flow_depth.csv.header.flowdepth"; + private static final String CSV_FLOWDEPTHTKH_HEADER = "sinfo.export.flow_depth.csv.header.flowdepthTkh"; + private static final String CSV_TKH_HEADER = "sinfo.export.flow_depth.csv.header.tkh"; + private static final String CSV_WATERLEVEL_HEADER = "sinfo.export.flow_depth.csv.header.waterlevel"; + private static final String CSV_DISCHARGE_HEADER = "sinfo.export.flow_depth.csv.header.discharge"; + private static final String CSV_LABEL_HEADER = "sinfo.export.flow_depth.csv.header.label"; + private static final String CSV_GAUGE_HEADER = "sinfo.export.flow_depth.csv.header.gauge"; + private static final String CSV_MEAN_BED_HEIGHT_HEADER = "sinfo.export.flow_depth.csv.header.mean_bed_height"; + private static final String CSV_SOUNDING_HEADER = "sinfo.export.flow_depth.csv.header.sounding"; + private static final String CSV_LOCATION_HEADER = "sinfo.export.flow_depth.csv.header.location"; + + private static final String CSV_META_HEADER_RESULT = + "sinfo.export.flow_depth.csv.meta.header.result"; + + private static final String CSV_META_VERSION = + "sinfo.export.flow_depth.csv.meta.version"; + + private static final String CSV_META_USER = + "sinfo.export.flow_depth.csv.meta.user"; + + private static final String CSV_META_CREATION = + "sinfo.export.flow_depth.csv.meta.creation"; + + private static final String CSV_META_RIVER = + "sinfo.export.flow_depth.csv.meta.river"; + + private static final String CSV_META_HEADER_SOUNDING = + "sinfo.export.flow_depth.csv.meta.header.sounding"; + + private static final String CSV_META_HEADER_WATERLEVEL = + "sinfo.export.flow_depth.csv.meta.header.waterlevel"; + + private static final String JASPER_FILE = "/jasper/sinfo.flowdepth.jasper"; //$NON-NLS-1$ + + /** The storage that contains the current calculation result.*/ + private FlowDepthCalculationResults data = null; + + private NumberFormat meanBedHeightFormatter; + + private NumberFormat tkhFormatter; + + private NumberFormat flowDepthFormatter; + + private NumberFormat getMeanBedHeightFormatter() { + if( meanBedHeightFormatter == null ) + // FIXME: check if this is right + meanBedHeightFormatter = Formatter.getMiddleBedHeightHeight(context); + return meanBedHeightFormatter; + } + + private NumberFormat getTkhFormatter() { + if( tkhFormatter == null ) + // FIXME: check if this is right, probably not, we need one digit + tkhFormatter = Formatter.getWaterlevelW(context); + return tkhFormatter; + } + + private NumberFormat getFlowDepthFormatter() { + if( flowDepthFormatter == null ) + // FIXME: check if this is right + flowDepthFormatter = Formatter.getMeterFormat(context); + return flowDepthFormatter; + } + + @Override + protected void addData(Object d) { + /* reset */ + data = null; + + if (d instanceof CalculationResult) { + + final Object dat = ((CalculationResult)d).getData(); + if( dat != null ) + data = (FlowDepthCalculationResults)dat; + } + } + + @Override + protected void writeCSVData(CSVWriter writer) { + log.info("FlowDepthExporter.writeCSVData"); + + /* fetch calculation results */ + final FlowDepthCalculationResults results = data; + + /* write as csv */ + +// boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE; +// boolean isQ = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE; +// RiverUtils.WQ_INPUT input +// = RiverUtils.getWQInputMode((D4EArtifact)master); + + final boolean useTkh = results.isUseTkh(); + + writeCSVMeta(writer, results); + writeCSVHeader(writer, useTkh); + + for (final FlowDepthCalculationResult result : results.getResults()) { + writeCSVFlowDepthResult(writer, result, useTkh); + } + } + + private void writeCSVFlowDepthResult(final CSVWriter writer, final FlowDepthCalculationResult result, final boolean useTkh) { + final Collection rows = result.getRows(); + for (final FlowDepthRow flowDepthRow : rows) { + writeCSVFlowDepthRow(writer, flowDepthRow, useTkh); + } + } + + private void writeCSVMeta(final CSVWriter writer, final FlowDepthCalculationResults results) { + log.info("FlowDepthExporter.writeCSVMeta"); + + // Workflow zur Berechnung der Fließtiefe.pdf + // "##ERGEBNISAUSGABE - Name des Gewässers - Fließtiefe" + final River river = results.getRiver(); + writeCSVMeataEntry(writer, CSV_META_HEADER_RESULT, river.getName() ); + + // "# FLYS-Version: " + // FIXME + final String flysVersion = "unbekannt"; + writeCSVMeataEntry(writer, CSV_META_VERSION, flysVersion ); + + // "# Bearbeiter: " + // FIXME + final String user = "unbekannt"; + writeCSVMeataEntry(writer, CSV_META_USER, user ); + + // "# Datum der Erstellung: " + final Locale locale = Resources.getLocale(context.getMeta()); + final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + writeCSVMeataEntry(writer, CSV_META_CREATION, df.format(new Date()) ); + + // "# Gewässer: " + writeCSVMeataEntry(writer, CSV_META_RIVER, river.getName() ); + + // "# Höhensystem des Flusses: " + + // FIXME + + // "# Ort/Bereich (km): " + // FIXME + // TODO: unklar, es wird nur ein Bereich eingegeben +// RangeAccess rangeAccess = new RangeAccess(flys); +// double[] kms = rangeAccess.getKmRange(); +// writer.writeNext(new String[] { +// Resources.getMsg( +// meta, +// CSV_META_RANGE, +// CSV_META_RANGE, +// new Object[] { kms[0], kms[kms.length-1] }) +// }); + + // "##METADATEN PEILUNG" + writeCSVMeataEntry(writer, CSV_META_HEADER_SOUNDING ); + +// "# Jahr der Peilung: " + // FIXME +// "# Aufnahmeart: " + // FIXME +// "# Lagesystem: " + // FIXME +// "# Höhensystem: " + // FIXME +// "# ursprüngliches Höhensystem: " + // FIXME +// "##METADATEN WASSERSPIEGELLAGE" + writeCSVMeataEntry(writer, CSV_META_HEADER_WATERLEVEL ); +// "# Bezeichnung der Wasserspiegellage: " + // FIXME +// "# Höhensystem der Wasserspiegellage: " + // FIXME +// "# Auswerter: " + // FIXME +// "# Bezugspegel: " + // FIXME +// "# Jahr/Zeitraum der Wasserspiegellage: " + // FIXME + + // "# W/Pegel [cm]: " (nur bei Eingabe des Wasserstands am Pegel) + // TODO: unklar, es wird kein W eingegeben + + // "# Q (m³/s): " (nur bei Eingabe des Durchflusses) + // TODO: unklar, es wird kein Q eingegeben + +// writer.writeNext(new String[] { +// Resources.getMsg( +// meta, +// CSV_META_GAUGE, +// CSV_META_GAUGE, +// new Object[] { RiverUtils.getGaugename(flys) }) +// }); + + writer.writeNext(new String[] { "" }); + } + + + private void writeCSVMeataEntry(CSVWriter writer, String message, Object... messageArgs) { + + CallMeta meta = context.getMeta(); + + writer.writeNext(new String[] { + Resources.getMsg( + meta, + message, + message, + messageArgs) + }); + } + + /** + * Write the header, with different headings depending on whether at a + * gauge or at a location. + * @param useTkh + */ + private void writeCSVHeader( + final CSVWriter writer, + final boolean useTkh + ) { + log.info("FlowDepthExporter.writeCSVHeader"); + + final Collection header = new ArrayList<>(11); + + header.add(msg(CSV_KM_HEADER,CSV_KM_HEADER)); + header.add(msg(CSV_FLOWDEPTH_HEADER)); + if( useTkh ) + { + header.add(msg(CSV_FLOWDEPTHTKH_HEADER)); + header.add(msg(CSV_TKH_HEADER)); + } + header.add(msg(CSV_WATERLEVEL_HEADER)); + header.add(msg(CSV_DISCHARGE_HEADER)); + header.add(msg(CSV_LABEL_HEADER)); + header.add(msg(CSV_GAUGE_HEADER)); + header.add(msg(CSV_MEAN_BED_HEIGHT_HEADER)); + header.add(msg(CSV_SOUNDING_HEADER)); + header.add(msg(CSV_LOCATION_HEADER)); + + writer.writeNext(header.toArray(new String[header.size()])); + } + + /** + * Format a row of a flow depth result into an array of string, both used by csv and pdf + * @param useTkh + */ + private String[] formatFlowDepthRow( + final FlowDepthRow row, + boolean useTkh ) { + + final Collection lines = new ArrayList<>(11); + + // Fluss-km + lines.add( getKmFormatter().format( row.getStation() ) ); + + // Fließtiefe [m] + lines.add( getFlowDepthFormatter().format( row.getFlowDepth() ) ); + + if( useTkh ) + { + // Fließtiefe mit TKH [m] + lines.add( getFlowDepthFormatter().format( row.getFlowDepthWithTkh() ) ); + + // TKH [cm] + lines.add( getTkhFormatter().format( row.getTkh() ) ); + } + + // Wasserstand [NN + m] + lines.add( getWFormatter().format( row.getWaterlevel() ) ); + + // Q [m³/s] + lines.add( getQFormatter().format( row.getDischarge() ) ); + + // Bezeichnung + lines.add( row.getWaterlevelLabel() ); + + // Bezugspegel + lines.add( row.getGauge() ); + + // Mittlere Sohlhöhe [NN + m] + lines.add( getMeanBedHeightFormatter().format( row.getMeanBedHeight( ) ) ); + + // Peilung/Epoche + lines.add( row.getSoundageLabel() ); + + // Lage + lines.add( row.getLocation() ); + + return lines.toArray(new String[lines.size()]); + } + /** + * Write "rows" of csv data from wqkms with writer. + * @param useTkh + */ + private void writeCSVFlowDepthRow( + final CSVWriter writer, + final FlowDepthRow row, + final boolean useTkh + ) { + log.debug("FlowDepthExporter.writeCSVFlowDepthRow"); + + final String[] formattedRow = formatFlowDepthRow(row, useTkh); + writer.writeNext( formattedRow ); + } + + @Override + protected void writePDF(OutputStream outStream) { + log.debug("write PDF"); + + final JRDataSource source = createJRData(); + + final String confPath = Config.getConfigDirectory().toString(); + + // FIXME: distinguish between with and without tkh: we need two jasper reports! + + final Map parameters = new HashMap<>(); + parameters.put("ReportTitle", "Exported Data"); + try { + final JasperPrint print = JasperFillManager.fillReport( + confPath + JASPER_FILE, + parameters, + source); + JasperExportManager.exportReportToPdfStream(print, outStream); + } + catch(JRException je) { + log.warn("Error generating PDF Report!", je); + } + } + + private JRDataSource createJRData() { + + /* fetch calculation results */ + final FlowDepthCalculationResults results = data; + + final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource(); + + addJRMetaData(source, results); + + final boolean useTkh = results.isUseTkh(); + + for (final FlowDepthCalculationResult result : results.getResults()) { + addJRTableData(source, result, useTkh); + } + + return source; + } + + private void addJRMetaData(final MetaAndTableJRDataSource source, FlowDepthCalculationResults results) { + + // Workflow zur Berechnung der Fließtiefe.pdf + // "##ERGEBNISAUSGABE - Name des Gewässers - Fließtiefe" + // writeCSVMeataEntry(writer, CSV_META_HEADER_RESULT, inputData.getRiver() ); + + // FIXME + final String flysVersion = "unbekannt"; + // CSV_META_VERSION + source.addMetaData("version", flysVersion); + + // FIXME + String user = "unbekannt"; + // CSV_META_USER + source.addMetaData("user", user); + + final Locale locale = Resources.getLocale(context.getMeta()); + final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + source.addMetaData("date", df.format(new Date())); + + // CSV_META_RIVER + source.addMetaData("river", results.getRiver().getName()); + + // FIXME + source.addMetaData("range", "FIXME"); + // "# Ort/Bereich (km): " + // FIXME + // TODO: unklar, es wird nur ein Bereich eingegeben +// RangeAccess rangeAccess = new RangeAccess(flys); +// double[] kms = rangeAccess.getKmRange(); +// writer.writeNext(new String[] { +// Resources.getMsg( +// meta, +// CSV_META_RANGE, +// CSV_META_RANGE, +// new Object[] { kms[0], kms[kms.length-1] }) +// }); + +// RangeAccess rangeAccess = new RangeAccess(flys); +// double[] kms = rangeAccess.getKmRange(); +// source.addMetaData("range", +// kmf.format(kms[0]) + " - " + kmf.format(kms[kms.length-1])); + } + + private void addJRTableData(final MetaAndTableJRDataSource source, final FlowDepthCalculationResult result, final boolean useTkh) { + + final Collection rows = result.getRows(); + + for (final FlowDepthRow row : rows) { + + final String[] formattedRow = formatFlowDepthRow(row, useTkh); + source.addData(formattedRow); + } + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthFilterFacet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthFilterFacet.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,98 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import org.apache.log4j.Logger; +import org.dive4elements.artifactdatabase.state.Facet; +import org.dive4elements.artifacts.Artifact; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.D4EArtifact; +import org.dive4elements.river.artifacts.model.CalculationResult; +import org.dive4elements.river.artifacts.model.DataFacet; +import org.dive4elements.river.artifacts.states.DefaultState.ComputeType; + +/** + * Facet of a FlowDepth curve. + */ +public class FlowDepthFilterFacet extends DataFacet { + + private static Logger log = Logger.getLogger(FlowDepthFilterFacet.class); + + public FlowDepthFilterFacet() { + // required for clone operation deepCopy() + } + + public FlowDepthFilterFacet( + int idx, + String name, + String description, + ComputeType type, + String stateId, + String hash + ) { + super(idx, name, description, type, hash, stateId); + this.metaData.put("X", "sinfo.chart.flow_depth.xaxis.label"); + this.metaData.put("Y", "sinfo.chart.flow_depth.yaxis.label"); + } + + @Override + public Object getData(Artifact artifact, CallContext context) { + log.debug("Get data for flow velocity at index: " + index); + + final D4EArtifact flys = (D4EArtifact) artifact; + + final CalculationResult res = (CalculationResult) + flys.compute(context, hash, stateId, type, false); + + final FlowDepthCalculationResults data = (FlowDepthCalculationResults) res.getData(); + + final FlowDepthCalculationResult result = data.getResults().get(index); + + // FIXME: variable mean computation depending on current scale +// Double start = (Double)context.getContextValue("startkm"); +// Double end = (Double)context.getContextValue("endkm"); +// if(start != null && end != null) { +// RiverContext fc = (RiverContext)context.globalContext(); +// ZoomScale scales = (ZoomScale)fc.get("zoomscale"); +// RiverAccess access = new RiverAccess((D4EArtifact)artifact); +// String river = access.getRiverName(); +// +// double radius = scales.getRadius(river, start, end); +// FlowVelocityData oldData = data[index]; +// FlowVelocityData newData = new FlowVelocityData(); +// double[][] q = oldData.getQPoints(); +// double[][] totalV = MovingAverage.weighted(oldData.getTotalChannelPoints(), radius); +// double[][] mainV = MovingAverage.weighted(oldData.getMainChannelPoints(), radius); +// double[][] tau = MovingAverage.weighted(oldData.getTauPoints(), radius); +// for(int j = 0; j < q[0].length; j++) { +// newData.addKM(q[0][j]); +// newData.addQ(q[1][j]); +// newData.addTauMain(tau[1][j]); +// newData.addVMain(mainV[1][j]); +// newData.addVTotal(totalV[1][j]); +// } +// return newData; +// } + + return result; + } + + + /** Copy deeply. */ + @Override + public Facet deepCopy() { + FlowDepthFilterFacet copy = new FlowDepthFilterFacet(); + // FIXME: why does DataFacet does not override set? Bad access to variables of parent! + copy.set(this); + copy.type = type; + copy.hash = hash; + copy.stateId = stateId; + return copy; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthPairSelectState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthPairSelectState.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,27 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import org.dive4elements.river.artifacts.states.WaterlevelPairSelectState; + +/** + * @author Gernot Belger + * + */ +public class FlowDepthPairSelectState +// FIXME: very ugly; but probably we will break the serialization of WaterlevelPairSelectState if we introduce an abstraction +extends WaterlevelPairSelectState { + + /** Specify to display a datacage_twin_panel. */ + @Override + protected String getUIProvider() { + return "sinfo_flowdepth_twin_panel"; + } +} diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthProcessor.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,105 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import java.util.Map; + +import org.apache.log4j.Logger; +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.exports.DiagramGenerator; +import org.dive4elements.river.exports.StyledSeriesBuilder; +import org.dive4elements.river.exports.process.DefaultProcessor; +import org.dive4elements.river.jfree.StyledXYSeries; +import org.dive4elements.river.themes.ThemeDocument; + +public final class FlowDepthProcessor extends DefaultProcessor { + + /* Theme name, usually defined in 'FacetTypes', but that is soooo bad dependencies... */ + static String FACET_FLOW_DEPTH_FILTERED = "sinfo_flow_depth.filtered"; + + private final static Logger log = Logger.getLogger(FlowDepthProcessor.class); + + private static final String I18N_AXIS_LABEL = "sinfo.chart.flow_depth.section.yaxis.label"; + private String yAxisLabel; + + @Override + public void doOut( + final DiagramGenerator generator, + final ArtifactAndFacet bundle, + final ThemeDocument theme, + final boolean visible) { + + final CallContext context = generator.getCallContext(); + final Map metaData = bundle.getFacet().getMetaData(); + + final StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); + series.putMetaData(metaData, bundle.getArtifact(), context); + + yAxisLabel = metaData.get("Y"); + + final String facetName = bundle.getFacetName(); + final FlowDepthCalculationResult data = (FlowDepthCalculationResult) bundle.getData(context); + if (data == null) { + // Check has been here before so we keep it for security reasons + // this should never happen though. + log.error("Data is null for facet: " + facetName); + return; + } + + final double [][] points = generatePoints(data); + + StyledSeriesBuilder.addPoints(series, points, true); + generator.addAxisSeries(series, axisName, visible); + } + + private static double[][] generatePoints(final FlowDepthCalculationResult data) { + + // FIXME + return data.getFlowDepthPoints(); + +// if (facetName.equals(FacetTypes.FLOW_VELOCITY_TOTALCHANNEL) || +// facetName.equals(FacetTypes.FLOW_VELOCITY_TOTALCHANNEL_FILTERED)) { +// FlowVelocityData fData = (FlowVelocityData) data; +// points = fData.getTotalChannelPoints(); +// } else if (facetName.equals(FacetTypes.FLOW_VELOCITY_MAINCHANNEL) || +// facetName.equals(FacetTypes.FLOW_VELOCITY_MAINCHANNEL_FILTERED)) { +// FlowVelocityData fData = (FlowVelocityData) data; +// points = fData.getMainChannelPoints(); // I hate facets! +// } else if (facetName.equals(FacetTypes.FLOW_VELOCITY_MEASUREMENT)) { +// FastFlowVelocityMeasurementValue fData = +// (FastFlowVelocityMeasurementValue) data; +// points = new double[][] {{fData.getStation()},{fData.getV()}}; +// } else { +// log.error("Unknown facet name: " + facetName); +// return; +// } + } + + @Override + public boolean canHandle(String facettype) { + return FACET_FLOW_DEPTH_FILTERED.equals(facettype); + } + + @Override + public String getAxisLabel(DiagramGenerator generator) { + if (yAxisLabel != null && !yAxisLabel.isEmpty()) { + // REMARK/UNINTENDED: yAxisLabel may also be a resolved message (side-effect of StyledXYSeries#putMetadata), + // and cannot be resolved, so we need to give the resolved value as default + // In other implementations (i.e. FlowVelocityProcessor), an explicit (German) default label is given here, probably + // the English version will also show German (CHECK) + return generator.msg(yAxisLabel, yAxisLabel); + } + return generator.msg( + I18N_AXIS_LABEL, + "MISSING"); + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthRow.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthRow.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,90 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import java.io.Serializable; + +/** + * Part of {@link FlowDepthCalculationResult} which represents one calculated row of flow depth data. + * + * @author Gernot Belger + */ +final class FlowDepthRow +implements Serializable { + private final double station; + private final double flowDepth; + private final double flowDepthWithTkh; + private final double tkh; + private final double waterlevel; + private final double discharge; + private final String waterlevelLabel; + private final String gauge; + private final double meanBedHeight; + private final String soundageLabel; + private final String location; + + public FlowDepthRow( double station, double flowDepth, double flowDepthWithTkh, double tkh, double waterlevel, double discharge, String waterlevelLabel, String gauge, double meanBedHeight, String soundageLabel, String location ) { + this.station = station; + this.flowDepth = flowDepth; + this.flowDepthWithTkh = flowDepthWithTkh; + this.tkh = tkh; + this.waterlevel = waterlevel; + this.discharge = discharge; + this.waterlevelLabel = waterlevelLabel; + this.gauge = gauge; + this.meanBedHeight = meanBedHeight; + this.soundageLabel = soundageLabel; + this.location = location; + } + + public double getStation() { + return station; + } + + public double getFlowDepth() { + return flowDepth; + } + + public double getFlowDepthWithTkh() { + return flowDepthWithTkh; + } + + public double getTkh() { + return tkh; + } + + public double getWaterlevel() { + return waterlevel; + } + + public double getDischarge() { + return discharge; + } + + public String getWaterlevelLabel() { + return waterlevelLabel; + } + + public String getGauge() { + return gauge; + } + + public double getMeanBedHeight() { + return meanBedHeight; + } + + public String getSoundageLabel() { + return soundageLabel; + } + + public String getLocation() { + return location; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/FlowDepthState.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,140 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import java.util.List; + +import org.dive4elements.artifactdatabase.state.Facet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.ChartArtifact; +import org.dive4elements.river.artifacts.D4EArtifact; +import org.dive4elements.river.artifacts.model.Calculation; +import org.dive4elements.river.artifacts.model.CalculationResult; +import org.dive4elements.river.artifacts.model.DataFacet; +import org.dive4elements.river.artifacts.model.EmptyFacet; +import org.dive4elements.river.artifacts.model.FacetTypes; +import org.dive4elements.river.artifacts.model.ReportFacet; +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.sinfo.SINFOArtifact; +import org.dive4elements.river.artifacts.states.DefaultState; + +/** State in which a waterlevel has been calculated. */ +public class FlowDepthState +extends DefaultState +{ + /// ** The log that is used in this state. */ + // private static Logger log = Logger.getLogger(FlowDepthState.class); + + private static final String I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION = "sinfo.facet.flow_depth.filtered.description"; + + /** + * From this state can only be continued trivially. + */ + @Override + protected String getUIProvider() { + return "continue"; + } + + @Override + public Object computeFeed( + final D4EArtifact artifact, + final String hash, + final CallContext context, + final List facets, + final Object old + ) { + // FIXME: why is this necessary? + if (artifact instanceof ChartArtifact) { + facets.add(new EmptyFacet()); + return null; + } + return compute((SINFOArtifact) artifact, context, hash, facets, old); + } + + @Override + public Object computeAdvance( + final D4EArtifact artifact, + final String hash, + final CallContext context, + final List facets, + final Object old + ) { + if (artifact instanceof ChartArtifact) { + facets.add(new EmptyFacet()); + return null; + } + return compute((SINFOArtifact) artifact, context, hash, facets, old); + } + + /** + * Compute result or returned object from cache, create facets. + * @param old Object that was cached. + */ + private Object compute( + final SINFOArtifact sinfo, + final CallContext context, + final String hash, + final List facets, + final Object old + ) { + final CalculationResult res; + if (old instanceof CalculationResult) + res = (CalculationResult) old; + else + res = new FlowDepthCalculation(context).calculate(sinfo); + + if (facets == null) { + return res; + } + + final FlowDepthCalculationResults results = (FlowDepthCalculationResults) res.getData(); + + /* add themes for chart, for each result */ + final List resultList = results.getResults(); + for (int index = 0; index < resultList.size(); index++) { + + final FlowDepthCalculationResult result = resultList.get(index); + /* compute theme label */ + final String wspLabel = result.getWstLabel(); + final String soundingLabel = result.getSoundingLabel(); + final String inputLabel = String.format("%s - %s", wspLabel, soundingLabel); + + /* filtered (zoom dependent mean) flow depth */ + final String facetFlowDepthFilteredDescription = Resources.getMsg( context.getMeta(), I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION, I18N_FACET_FLOW_DEPTH_FILTERED_DESCRIPTION, inputLabel ); + facets.add(new FlowDepthFilterFacet( + index, + FlowDepthProcessor.FACET_FLOW_DEPTH_FILTERED, + facetFlowDepthFilteredDescription, + ComputeType.ADVANCE, + id, + hash + )); + + // FIXME: add other themes + } + + if (!resultList.isEmpty() ) { + Facet csv = new DataFacet( + FacetTypes.CSV, "CSV data", ComputeType.ADVANCE, hash, id); + Facet pdf = new DataFacet( + FacetTypes.PDF, "PDF data", ComputeType.ADVANCE, hash, id); + + facets.add(csv); + facets.add(pdf); + } + + final Calculation report = res.getReport(); + + if (report.hasProblems()) { + facets.add(new ReportFacet(ComputeType.ADVANCE, hash, id)); + } + + return res; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/UseTransportBodiesChoice.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/flowdepth/UseTransportBodiesChoice.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,21 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.sinfo.flowdepth; + +import org.dive4elements.river.artifacts.states.BooleanChoiceState; + +/** + * @author Ingo Weinzierl + */ +public class UseTransportBodiesChoice extends BooleanChoiceState { + + public UseTransportBodiesChoice() { + super( "useTransportBodies.option", "useTransportBodies.active", "useTransportBodies.inactive" ); + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/MetaAndTableJRDataSource.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/util/MetaAndTableJRDataSource.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,64 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.sinfo.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.sf.jasperreports.engine.JRDataSource; +import net.sf.jasperreports.engine.JRException; +import net.sf.jasperreports.engine.JRField; + +/** + * @author Raimund Renkert + */ +public final class MetaAndTableJRDataSource implements JRDataSource +{ + private List data = new ArrayList<>(); + + private Map metaData = new HashMap<>(); + + private int index = -1; + + public void addData(final String[] data) { + this.data.add(data); + } + + public void addMetaData(final String key, final String value) { + this.metaData.put(key, value); + } + + @Override + public boolean next() throws JRException + { + index++; + + return index < data.size(); + } + + @Override + public Object getFieldValue(final JRField field) throws JRException + { + final String fieldName = field.getName(); + + if( fieldName.startsWith("meta:")) + return metaData.get(fieldName.substring("meta:".length())); + + if( fieldName.startsWith("data:")) + { + int column = Integer.valueOf(fieldName.substring("data:".length())); + return data.get(index)[column]; + } + + return null; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/states/BooleanChoiceState.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/BooleanChoiceState.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,100 @@ +/* Copyright (C) 2011, 2012, 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.artifacts.states; + +import org.w3c.dom.Element; + +import org.apache.log4j.Logger; + +import org.dive4elements.artifacts.Artifact; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.artifacts.CallMeta; + +import org.dive4elements.artifacts.common.utils.XMLUtils; + +import org.dive4elements.artifactdatabase.ProtocolUtils; + +import org.dive4elements.river.artifacts.resources.Resources; + +/** + * Generic state for a boolean choice. Only difference between real implementations are the human readable labels. + * + * @author Ingo Weinzierl + * @author Gernot Belger + */ +public abstract class BooleanChoiceState extends DefaultState { + + private String optionMsg; + private String activeMsg; + private String inactiveMsg; + + public BooleanChoiceState( String optionMsg, String activeMsg, String inactiveMsg ) { + this.optionMsg = optionMsg; + this.activeMsg = activeMsg; + this.inactiveMsg = inactiveMsg; + } + + private static final Logger log = + Logger.getLogger(BooleanChoiceState.class); + + @Override + protected String getUIProvider() { + return "boolean_panel"; + } + + @Override + protected Element[] createItems( + XMLUtils.ElementCreator cr, + Artifact artifact, + String name, + CallContext context) + { + CallMeta meta = context.getMeta(); + + Element option = createItem( + cr, + new String[] { Resources.getMsg(meta, optionMsg, optionMsg), "true" }); + + return new Element[] { option }; + } + + + @Override + protected String getLabelFor( + CallContext cc, + String name, + String value, + String type + ) { + log.debug("GET LABEL FOR '" + name + "' / '" + value + "'"); + if (value != null && value.equals("true")) { + return Resources.getMsg(cc.getMeta(), activeMsg, activeMsg); + } + else { + return Resources.getMsg(cc.getMeta(), inactiveMsg, inactiveMsg); + } + } + + + protected Element createItem(XMLUtils.ElementCreator cr, Object obj) { + Element item = ProtocolUtils.createArtNode(cr, "item", null, null); + Element label = ProtocolUtils.createArtNode(cr, "label", null, null); + Element value = ProtocolUtils.createArtNode(cr, "value", null, null); + + String[] arr = (String[]) obj; + + label.setTextContent(arr[0]); + value.setTextContent(arr[1]); + + item.appendChild(label); + item.appendChild(value); + + return item; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/states/FloodplainChoice.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/FloodplainChoice.java Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/FloodplainChoice.java Fri Jan 19 11:23:42 2018 +0100 @@ -26,6 +26,7 @@ /** * @author Ingo Weinzierl */ +// FIXME: inherit from BooleanChoiceState instead to remove duplicate code; BUT: this will probably break artifact serialization public class FloodplainChoice extends DefaultState { public static final String OPTION = "floodplain.option"; diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/states/WDifferencesState.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WDifferencesState.java Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WDifferencesState.java Fri Jan 19 11:23:42 2018 +0100 @@ -109,6 +109,7 @@ /** * Access the data (wkms) of an artifact, coded in mingle. */ + // FIXME: meanwhile used by several places outside this context; refactor into separate helper class to access waterlevels public WKms getWKms( String mingle, CallContext context, diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelPairSelectState.java --- a/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelPairSelectState.java Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/states/WaterlevelPairSelectState.java Fri Jan 19 11:23:42 2018 +0100 @@ -48,7 +48,7 @@ /** Specify to display a datacage_twin_panel. */ @Override protected String getUIProvider() { - return "datacage_twin_panel"; + return "waterlevel_twin_panel"; } diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/exports/process/FlowVelocityProcessor.java --- a/artifacts/src/main/java/org/dive4elements/river/exports/process/FlowVelocityProcessor.java Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/FlowVelocityProcessor.java Fri Jan 19 11:23:42 2018 +0100 @@ -94,6 +94,9 @@ @Override public String getAxisLabel(DiagramGenerator generator) { if (yAxisLabel != null && !yAxisLabel.isEmpty()) { + // FIXME/UNINTENDED: yAxisLabel is probably a resolved message (side-effect of StyledXYSeries#putMetadata), + // and cannot be resolved again. + // An explicit (German) default label is therefore given here, probably the English version will also show German (CHECK) return generator.msg(yAxisLabel, I18N_AXIS_LABEL_DEFAULT); } return generator.msg( diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYSeries.java --- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYSeries.java Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYSeries.java Fri Jan 19 11:23:42 2018 +0100 @@ -146,6 +146,7 @@ @Override + // FIXME: bad! method with undocumented side-effects; given metadata will be changed inline public void putMetaData(Map metaData, Artifact artifact, CallContext context) { @@ -155,6 +156,7 @@ String unit = ""; if (river != null) { rivername = river.getName(); + // FIXME: this will always return the wst unit, regardless if the series is a water level or not! unit = river.getWstUnit().getName(); } if (metaData.containsKey("X")) { diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/java/org/dive4elements/river/utils/GaugeIndex.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/utils/GaugeIndex.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,52 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.utils; + +import java.util.List; + +import org.dive4elements.river.model.Gauge; + +/** + * Allows performant access to gauges by station. + * @author Gernot Belger + */ +public class GaugeIndex { + private List gauges; + + private Gauge lastGauge = null; + + public GaugeIndex( List gauges) { + this.gauges = gauges; + } + + public Gauge findGauge(double km) { + + // REMARK: this is code copied from WaterlevelExporter, which is honestly not very fast/good. + // Instead we need to index by range with an RTree and directly acccess the right gauge. + + if( lastGauge != null && lastGauge.getRange().contains(km) ) + return lastGauge; + + final Gauge gauge = findGauge(km, gauges); + + lastGauge = gauge; + + return gauge; + } + + private static Gauge findGauge(double km, List gauges) { + for (Gauge gauge: gauges) { + if (gauge.getRange().contains(km)) { + return gauge; + } + } + return null; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/resources/messages.properties --- a/artifacts/src/main/resources/messages.properties Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/resources/messages.properties Fri Jan 19 11:23:42 2018 +0100 @@ -761,3 +761,65 @@ help.state.fix.vollmer.preprocessing=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.preprocessing help.state.fix.vollmer.qs=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.qs help.state.fix.vollmer.compute=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.compute + +state.sinfo.river = River +state.sinfo.calculation_mode=Calculation Mode + +sinfo_calc_flow_depth=Flie\u00dftiefen +sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung +sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe +sinfo_calc_grounding=Grundber\u00fchrungen +sinfo_calc_transport_bodies_heights=Transportk\u00f6rperh\u00f6hen +sinfo_calc_infrastructures_inundation_duration=\u00dcberflutungsdauern Infrastrukturen BWaStr + +help.state.sinfo=${help.url}/OnlineHilfe/SINFO +help.state.sinfo.river=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.river +help.state.sinfo.calculation_mode=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.calculation_mode + +state.sinfo.distance_only = Range selection +help.state.sinfo.distance_only=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.distance_only + +state.sinfo.waterlevel_soundings_select= Chosen Differences +help.state.sinfo.waterlevel_soundings_select=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.waterlevel_soundings_select + +state.sinfo.use_transport_bodies=Transportk\u00f6rperh\u00f6hen +help.state.sinfo.use_transport_bodies=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.use_transport_bodies + +useTransportBodies.option = Transportk\u00f6rperh\u00f6hen miteinbeziehen? +useTransportBodies.active = Activ +useTransportBodies.inactive = Inactiv + +sinfo.export.flow_depth.csv.meta.header.result = ## Calculation Output - {0} - Flie\u00dftiefe - FLYS 3 +sinfo.export.flow_depth.csv.meta.version = # FLYS-Version: {0} +sinfo.export.flow_depth.csv.meta.user = # Bearbeiter: {0} +sinfo.export.flow_depth.csv.meta.creation = # Time of creation: {0} +sinfo.export.flow_depth.csv.meta.river = # River: {0} +sinfo.export.flow_depth.csv.meta.header.sounding = ##METADATEN PEILUNG +sinfo.export.flow_depth.csv.meta.header.waterlevel = ##METADATEN WASSERSPIEGELLAGE + +#export.export.flow_depth.csv.meta.range = # Location/Range (km): {0} - {1} +#export.export.flow_depth.csv.meta.gauge = # Gauge: {0} +#export.export.flow_depth.csv.meta.q = # Q (m\u00b3/s): {0} +#export.export.flow_depth.csv.meta.w = # W (NN + m): {0} - {1} + +sinfo.export.flow_depth.csv.header.km = Fluss-km +sinfo.export.flow_depth.csv.header.flowdepth = Flie\u00dftiefe [m] +sinfo.export.flow_depth.csv.header.flowdepthTkh = Flie\u00dftiefe mit TKH [m] +sinfo.export.flow_depth.csv.header.tkh = Flie\u00dftiefe mit TKH [cm] +# FIXME: H\u00f6henbezugssystem? +sinfo.export.flow_depth.csv.header.waterlevel = Wasserstand [NN+m] +sinfo.export.flow_depth.csv.header.discharge = Q [m\u00b3/s] +sinfo.export.flow_depth.csv.header.label = Bezeichnung +sinfo.export.flow_depth.csv.header.gauge = Bezugspegel +# FIXME: H\u00f6henbezugssystem? +sinfo.export.flow_depth.csv.header.mean_bed_height = Mittlere Sohlh\u00f6he [NN+m] +sinfo.export.flow_depth.csv.header.sounding = Peilung/Epoche +sinfo.export.flow_depth.csv.header.location = Lage + +sinfo.chart.flow_depth.section.title=h-L\u00e4ngsschnitt + +sinfo.chart.flow_depth.xaxis.label = {0}-km +sinfo.chart.flow_depth.yaxis.label = Flie\u00dftiefe [m] + +sinfo.chart.flow_depth.section.yaxis.label=Flie\u00dftiefe h [m] +sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0}) diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/resources/messages_de.properties --- a/artifacts/src/main/resources/messages_de.properties Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/resources/messages_de.properties Fri Jan 19 11:23:42 2018 +0100 @@ -36,10 +36,10 @@ state.fix.analysis.referenceperiod = Bezugszeitraum state.fix.analysis.analysisperiods = Analysezeitr\u00e4ume state.fix.analysis.function = Ausgleichsfunktion -state.fix.analysis.preprocessing = Ausrei\u00DFer +state.fix.analysis.preprocessing = Ausrei\u00dfer state.fix.preprocess=Ausrei\u00dfertest durchf\u00fchren state.fix.vollmer.function= Ausgleichsfunktion -state.fix.vollmer.preprocessing = Ausrei\u00DFer +state.fix.vollmer.preprocessing = Ausrei\u00dfer state.fix.vollmer.qs = Eingabe f\u00fcr W/Q Daten state.minfo.river = Gew\u00e4sser @@ -286,7 +286,7 @@ facet.sedimentload.calc.bed_load = Geschiebefracht (Berechnung FLYS) - {0} [{1}] facet.sedimentload.calc.bed_load_susp_sand = bettbildende Fracht (Berechnung FLYS) - {0} [{1}] -minfo.sedimentload.no.data = Keine Sedimentfracht-Daten verfügbar +minfo.sedimentload.no.data = Keine Sedimentfracht-Daten verf\u00fcgbar sedimentload.missing.fraction.coarse = Fehlende Fraktion Grober Kies/Steine - {0} sedimentload.missing.fraction.fine_middle = Fehlende Fraktion Fein/Mittlerer Kies - {0} sedimentload.missing.fraction.sand = Fehlende Fraktion Sand - {0} @@ -730,6 +730,7 @@ static.sq.station = Messstelle module.winfo = W-INFO +module.sinfo = S-INFO module.minfo = M-INFO module.fixanalysis = Fixierungsanalyse module.new_map = Neue Karte @@ -766,3 +767,65 @@ help.state.fix.vollmer.preprocessing=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.preprocessing help.state.fix.vollmer.qs=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.qs help.state.fix.vollmer.compute=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.compute + +state.sinfo.river = Gew\u00e4sser +state.sinfo.calculation_mode=Berechnungsart + +sinfo_calc_flow_depth=Flie\u00dftiefen +sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung +sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe +sinfo_calc_grounding=Grundber\u00fchrungen +sinfo_calc_transport_bodies_heights=Transportk\u00f6rperh\u00f6hen +sinfo_calc_infrastructures_inundation_duration=\u00dcberflutungsdauern Infrastrukturen BWaStr + +help.state.sinfo=${help.url}/OnlineHilfe/SINFO +help.state.sinfo.river=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.river +help.state.sinfo.calculation_mode=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.calculation_mode + +state.sinfo.distance_only = Wahl der Berechnungsstrecke +help.state.sinfo.distance_only=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.distance_only + +state.sinfo.waterlevel_soundings_select= Ausgew\u00e4hlte Differenzen +help.state.sinfo.waterlevel_soundings_select=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.waterlevel_soundings_select + +state.sinfo.use_transport_bodies=Transportk\u00f6rperh\u00f6hen +help.state.sinfo.use_transport_bodies=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.use_transport_bodies + +useTransportBodies.option = Transportk\u00f6rperh\u00f6hen miteinbeziehen? +useTransportBodies.active = Aktiv +useTransportBodies.inactive = Inaktiv + +sinfo.export.flow_depth.csv.meta.header.result = ## Ergebnisausgabe - {0} - Flie\u00dftiefe - FLYS 3 +sinfo.export.flow_depth.csv.meta.version = # FLYS-Version: {0} +sinfo.export.flow_depth.csv.meta.user = # Bearbeiter: {0} +sinfo.export.flow_depth.csv.meta.creation = # Datum der Erstellung: {0} +sinfo.export.flow_depth.csv.meta.river = # Gew\u00e4sser: {0} +sinfo.export.flow_depth.csv.meta.header.sounding = ##METADATEN PEILUNG +sinfo.export.flow_depth.csv.meta.header.waterlevel = ##METADATEN WASSERSPIEGELLAGE + +#export.export.flow_depth.csv.meta.range = # Location/Range (km): {0} - {1} +#export.export.flow_depth.csv.meta.gauge = # Gauge: {0} +#export.export.flow_depth.csv.meta.q = # Q (m\u00b3/s): {0} +#export.export.flow_depth.csv.meta.w = # W (NN + m): {0} - {1} + +sinfo.export.flow_depth.csv.header.km = Fluss-km +sinfo.export.flow_depth.csv.header.flowdepth = Flie\u00dftiefe [m] +sinfo.export.flow_depth.csv.header.flowdepthTkh = Flie\u00dftiefe mit TKH [m] +sinfo.export.flow_depth.csv.header.tkh = Flie\u00dftiefe mit TKH [cm] +# FIXME: H\u00f6henbezugssystem? +sinfo.export.flow_depth.csv.header.waterlevel = Wasserstand [NN+m] +sinfo.export.flow_depth.csv.header.discharge = Q [m\u00b3/s] +sinfo.export.flow_depth.csv.header.label = Bezeichnung +sinfo.export.flow_depth.csv.header.gauge = Bezugspegel +# FIXME: H\u00f6henbezugssystem? +sinfo.export.flow_depth.csv.header.mean_bed_height = Mittlere Sohlh\u00f6he [NN+m] +sinfo.export.flow_depth.csv.header.sounding = Peilung/Epoche +sinfo.export.flow_depth.csv.header.location = Lage + +sinfo.chart.flow_depth.section.title=h-L\u00e4ngsschnitt + +sinfo.chart.flow_depth.xaxis.label = {0}-km +sinfo.chart.flow_depth.yaxis.label = Flie\u00dftiefe [m] + +sinfo.chart.flow_depth.section.yaxis.label=Flow Depth h [m] +sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0}) \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/resources/messages_de_DE.properties --- a/artifacts/src/main/resources/messages_de_DE.properties Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/resources/messages_de_DE.properties Fri Jan 19 11:23:42 2018 +0100 @@ -36,10 +36,10 @@ state.fix.analysis.referenceperiod = Bezugszeitraum state.fix.analysis.analysisperiods = Analysezeitr\u00e4ume state.fix.analysis.function = Ausgleichsfunktion -state.fix.analysis.preprocessing = Ausrei\u00DFer +state.fix.analysis.preprocessing = Ausrei\u00dfer state.fix.preprocess=Ausrei\u00dfertest durchf\u00fchren state.fix.vollmer.function= Ausgleichsfunktion -state.fix.vollmer.preprocessing = Ausrei\u00DFer +state.fix.vollmer.preprocessing = Ausrei\u00dfer state.fix.vollmer.qs = Eingabe f\u00fcr W/Q Daten state.minfo.river = Gew\u00e4sser @@ -283,7 +283,7 @@ facet.sedimentload.calc.bed_load = Geschiebefracht (Berechnung FLYS) - {0} [{1}] facet.sedimentload.calc.bed_load_susp_sand = bettbildende Fracht (Berechnung FLYS) - {0} [{1}] -minfo.sedimentload.no.data = Keine Sedimentfracht-Daten verfügbar +minfo.sedimentload.no.data = Keine Sedimentfracht-Daten verf\u00fcgbar sedimentload.missing.fraction.coarse = Fehlende Fraktion Grober Kies/Steine - {0} sedimentload.missing.fraction.fine_middle = Fehlende Fraktion Fein/Mittlerer Kies - {0} sedimentload.missing.fraction.sand = Fehlende Fraktion Sand - {0} @@ -763,3 +763,65 @@ help.state.fix.vollmer.preprocessing=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.preprocessing help.state.fix.vollmer.qs=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.qs help.state.fix.vollmer.compute=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.compute + +state.sinfo.river = Gew\u00e4sser +state.sinfo.calculation_mode=Berechnungsart + +sinfo_calc_flow_depth=Flie\u00dftiefen +sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung +sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe +sinfo_calc_grounding=Grundber\u00fchrungen +sinfo_calc_transport_bodies_heights=Transportk\u00f6rperh\u00f6hen +sinfo_calc_infrastructures_inundation_duration=\u00dcberflutungsdauern Infrastrukturen BWaStr + +help.state.sinfo=${help.url}/OnlineHilfe/SINFO +help.state.sinfo.river=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.river +help.state.sinfo.calculation_mode=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.calculation_mode + +state.sinfo.distance_only = Wahl der Berechnungsstrecke +help.state.sinfo.distance_only=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.distance_only + +state.sinfo.waterlevel_soundings_select= Ausgew\u00e4hlte Differenzen +help.state.sinfo.waterlevel_soundings_select=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.waterlevel_soundings_select + +state.sinfo.use_transport_bodies=Transportk\u00f6rperh\u00f6hen +help.state.sinfo.use_transport_bodies=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.use_transport_bodies + +useTransportBodies.option = Transportk\u00f6rperh\u00f6hen miteinbeziehen? +useTransportBodies.active = Aktiv +useTransportBodies.inactive = Inaktiv + +sinfo.export.flow_depth.csv.meta.header.result = ## Ergebnisausgabe - {0} - Flie\u00dftiefe - FLYS 3 +sinfo.export.flow_depth.csv.meta.version = # FLYS-Version: {0} +sinfo.export.flow_depth.csv.meta.user = # Bearbeiter: {0} +sinfo.export.flow_depth.csv.meta.creation = # Datum der Erstellung: {0} +sinfo.export.flow_depth.csv.meta.river = # Gew\u00e4sser: {0} +sinfo.export.flow_depth.csv.meta.header.sounding = ##METADATEN PEILUNG +sinfo.export.flow_depth.csv.meta.header.waterlevel = ##METADATEN WASSERSPIEGELLAGE + +#export.export.flow_depth.csv.meta.range = # Location/Range (km): {0} - {1} +#export.export.flow_depth.csv.meta.gauge = # Gauge: {0} +#export.export.flow_depth.csv.meta.q = # Q (m\u00b3/s): {0} +#export.export.flow_depth.csv.meta.w = # W (NN + m): {0} - {1} + +sinfo.export.flow_depth.csv.header.km = Fluss-km +sinfo.export.flow_depth.csv.header.flowdepth = Flie\u00dftiefe [m] +sinfo.export.flow_depth.csv.header.flowdepthTkh = Flie\u00dftiefe mit TKH [m] +sinfo.export.flow_depth.csv.header.tkh = Flie\u00dftiefe mit TKH [cm] +# FIXME: H\u00f6henbezugssystem? +sinfo.export.flow_depth.csv.header.waterlevel = Wasserstand [NN+m] +sinfo.export.flow_depth.csv.header.discharge = Q [m\u00b3/s] +sinfo.export.flow_depth.csv.header.label = Bezeichnung +sinfo.export.flow_depth.csv.header.gauge = Bezugspegel +# FIXME: H\u00f6henbezugssystem? +sinfo.export.flow_depth.csv.header.mean_bed_height = Mittlere Sohlh\u00f6he [NN+m] +sinfo.export.flow_depth.csv.header.sounding = Peilung/Epoche +sinfo.export.flow_depth.csv.header.location = Lage + +sinfo.chart.flow_depth.section.title=h-L\u00e4ngsschnitt + +sinfo.chart.flow_depth.xaxis.label = {0}-km +sinfo.chart.flow_depth.yaxis.label = Flie\u00dftiefe [m] + +sinfo.chart.flow_depth.section.yaxis.label=Flow Depth h [m] +sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0}) \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 artifacts/src/main/resources/messages_en.properties --- a/artifacts/src/main/resources/messages_en.properties Thu Jan 18 20:54:03 2018 +0100 +++ b/artifacts/src/main/resources/messages_en.properties Fri Jan 19 11:23:42 2018 +0100 @@ -762,3 +762,65 @@ help.state.fix.vollmer.preprocessing=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.preprocessing help.state.fix.vollmer.qs=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.qs help.state.fix.vollmer.compute=${help.url}/OnlineHilfe/Fixierungsanalyse#help.state.fix.vollmer.compute + +state.sinfo.river = River +state.sinfo.calculation_mode=Calculation Mode + +sinfo_calc_flow_depth=Flie\u00dftiefen +sinfo_calc_flow_depth_development=Flie\u00dftiefenentwicklung +sinfo_calc_flow_depth_minmax=Minimale und Maximale Flie\u00dftiefe +sinfo_calc_grounding=Grundber\u00fchrungen +sinfo_calc_transport_bodies_heights=Transportk\u00f6rperh\u00f6hen +sinfo_calc_infrastructures_inundation_duration=\u00dcberflutungsdauern Infrastrukturen BWaStr + +help.state.sinfo=${help.url}/OnlineHilfe/SINFO +help.state.sinfo.river=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.river +help.state.sinfo.calculation_mode=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.calculation_mode + +state.sinfo.distance_only = Range selection +help.state.sinfo.distance_only=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.distance_only + +state.sinfo.waterlevel_soundings_select= Chosen Differences +help.state.sinfo.waterlevel_soundings_select=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.waterlevel_soundings_select + +state.sinfo.use_transport_bodies=Transportk\u00f6rperh\u00f6hen +help.state.sinfo.use_transport_bodies=${help.url}/OnlineHilfe/SINFO#help.state.sinfo.use_transport_bodies + +useTransportBodies.option = Transportk\u00f6rperh\u00f6hen miteinbeziehen? +useTransportBodies.active = Activ +useTransportBodies.inactive = Inactiv + +sinfo.export.flow_depth.csv.meta.header.result = ## Calculation Output - {0} - Flie\u00dftiefe - FLYS 3 +sinfo.export.flow_depth.csv.meta.version = # FLYS-Version: {0} +sinfo.export.flow_depth.csv.meta.user = # Bearbeiter: {0} +sinfo.export.flow_depth.csv.meta.creation = # Time of creation: {0} +sinfo.export.flow_depth.csv.meta.river = # River: {0} +sinfo.export.flow_depth.csv.meta.header.sounding = ##METADATEN PEILUNG +sinfo.export.flow_depth.csv.meta.header.waterlevel = ##METADATEN WASSERSPIEGELLAGE + +#export.export.flow_depth.csv.meta.range = # Location/Range (km): {0} - {1} +#export.export.flow_depth.csv.meta.gauge = # Gauge: {0} +#export.export.flow_depth.csv.meta.q = # Q (m\u00b3/s): {0} +#export.export.flow_depth.csv.meta.w = # W (NN + m): {0} - {1} + +sinfo.export.flow_depth.csv.header.km = Fluss-km +sinfo.export.flow_depth.csv.header.flowdepth = Flie\u00dftiefe [m] +sinfo.export.flow_depth.csv.header.flowdepthTkh = Flie\u00dftiefe mit TKH [m] +sinfo.export.flow_depth.csv.header.tkh = Flie\u00dftiefe mit TKH [cm] +# FIXME: H\u00f6henbezugssystem? +sinfo.export.flow_depth.csv.header.waterlevel = Wasserstand [NN+m] +sinfo.export.flow_depth.csv.header.discharge = Q [m\u00b3/s] +sinfo.export.flow_depth.csv.header.label = Bezeichnung +sinfo.export.flow_depth.csv.header.gauge = Bezugspegel +# FIXME: H\u00f6henbezugssystem? +sinfo.export.flow_depth.csv.header.mean_bed_height = Mittlere Sohlh\u00f6he [NN+m] +sinfo.export.flow_depth.csv.header.sounding = Peilung/Epoche +sinfo.export.flow_depth.csv.header.location = Lage + +sinfo.chart.flow_depth.section.title=h-L\u00e4ngsschnitt + +sinfo.chart.flow_depth.xaxis.label = {0}-km +sinfo.chart.flow_depth.yaxis.label = Flie\u00dftiefe [m] + +sinfo.chart.flow_depth.section.yaxis.label=Flie\u00dftiefe h [m] +sinfo.facet.flow_depth.filtered.description = Flie\u00dftiefe ({0}) \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Fri Jan 19 11:23:42 2018 +0100 @@ -1421,5 +1421,15 @@ String error_no_sedimentloadinfo_found(); String error_no_sedimentloadinfo_data(); + + String sinfo(); + + String sinfo_flowdepth_export(); + + String sinfo_flowdepth_report(); + + String sinfo_flow_depth(); + + String sinfo_flowdepth_twinpanel_no_pair_selected(); } -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Fri Jan 19 11:23:42 2018 +0100 @@ -756,3 +756,9 @@ upper_time = to no_data_for_year = No data available for: $1 + +sinfo = S-INFO +sinfo_flowdepth_export = Flie\u00dftiefen Export +sinfo_flowdepth_report = Flie\u00dftiefen Bericht +sinfo_flow_depth = Flie\u00dftiefen +sinfo_flowdepth_twinpanel_no_pair_selected = Error - at least one input pair must be selected \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Fri Jan 19 11:23:42 2018 +0100 @@ -748,3 +748,9 @@ upper_time = bis no_data_for_year = F\u00fcr das Jahr $1 liegen keine Daten vor. + +sinfo = S-INFO +sinfo_flowdepth_export = Flie\u00dftiefen Export +sinfo_flowdepth_report = Flie\u00dftiefen Bericht +sinfo_flow_depth = Flie\u00dftiefen +sinfo_flowdepth_twinpanel_no_pair_selected = Fehler - kein Paar zur Differenzenbildung gew\u00e4hlt. \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_en.properties --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_en.properties Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_en.properties Fri Jan 19 11:23:42 2018 +0100 @@ -785,3 +785,9 @@ upper_time = to no_data_for_year = No data available for: $1 + +sinfo = S-INFO +sinfo_flowdepth_export = Flie\u00dftiefen Export +sinfo_flowdepth_report = Flie\u00dftiefen Bericht +sinfo_flow_depth = Flie\u00dftiefen +sinfo_flowdepth_twinpanel_no_pair_selected = Error - at least one input pair must be selected \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractPairRecommendationPanel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractPairRecommendationPanel.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,508 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.client.client.ui; + +import com.google.gwt.core.client.GWT; +import com.google.gwt.user.client.rpc.AsyncCallback; + +import com.smartgwt.client.data.Record; +import com.smartgwt.client.types.ListGridFieldType; +import com.smartgwt.client.widgets.Canvas; +import com.smartgwt.client.widgets.events.ClickEvent; +import com.smartgwt.client.widgets.grid.ListGrid; +import com.smartgwt.client.widgets.grid.ListGridField; +import com.smartgwt.client.widgets.grid.ListGridRecord; +import com.smartgwt.client.widgets.grid.events.RecordClickEvent; +import com.smartgwt.client.widgets.grid.events.RecordClickHandler; +import com.smartgwt.client.widgets.layout.VLayout; + +import org.dive4elements.river.client.client.Config; +import org.dive4elements.river.client.client.FLYSConstants; +import org.dive4elements.river.client.client.event.StepForwardEvent; +import org.dive4elements.river.client.client.services.LoadArtifactServiceAsync; +import org.dive4elements.river.client.client.services.RemoveArtifactServiceAsync; +import org.dive4elements.river.client.shared.model.Artifact; +import org.dive4elements.river.client.shared.model.Collection; +import org.dive4elements.river.client.shared.model.Data; +import org.dive4elements.river.client.shared.model.DataItem; +import org.dive4elements.river.client.shared.model.DataList; +import org.dive4elements.river.client.shared.model.DefaultData; +import org.dive4elements.river.client.shared.model.DefaultDataItem; +import org.dive4elements.river.client.shared.model.Recommendation; +import org.dive4elements.river.client.shared.model.Recommendation.Facet; +import org.dive4elements.river.client.shared.model.Recommendation.Filter; +import org.dive4elements.river.client.shared.model.User; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +// TODO Probably better to branch off AbstractUIProvider. +// TODO Merge with other datacage-widget impls. +/** + * Panel containing a Grid and a "next" button. The Grid is fed by a + * DatacagePairWidget which is put in the input-helper area. + */ +public abstract class AbstractPairRecommendationPanel +extends TextProvider { + + /** + * Allows for abstraction on how to handle/serialize the recommendation and the used factories. + * @author Gernot Belger + * + */ + public static interface IRecommendationInfo { + + String getFactory(); + + /** + * Separate factory for the 'createDataString' method, because in the case of waterlevels. See HOTFIX/FIXME there. + */ + String getDataStringFactory(); + + /** + * Set factory of recommendation such that the correct artifacts will + * be cloned for difference calculations. + */ + void adjustRecommendation(Recommendation recommendation); + } + + public static interface IValidator + { + List validate(ListGrid differencesList, FLYSConstants msgProvider); + } + + private static final long serialVersionUID = 8906629596491827857L; + + // FIXME: why? we hide the field of the super class with exactly the same thing... + private static FLYSConstants MSG_PROVIDER = GWT.create(FLYSConstants.class); + + private String dataName; + + private User user; + + /** ListGrid that displays user-selected pairs to build differences with. */ + private ListGrid differencesList; + + /** + * List to track previously selected but now removed pairs. (Needed to + * be able to identify artifacts that can be removed from the collection. + */ + private List removedPairs = + new ArrayList(); + + /** Service handle to clone and add artifacts to collection. */ + private LoadArtifactServiceAsync loadArtifactService = GWT.create( + org.dive4elements.river.client.client.services.LoadArtifactService.class); + + /** Service to remove artifacts from collection. */ + private RemoveArtifactServiceAsync removeArtifactService = GWT.create( + org.dive4elements.river.client.client.services.RemoveArtifactService.class); + + private IRecommendationInfo leftInfo; + + private IRecommendationInfo rightInfo; + + private IValidator validator; + + /** + * @param Validates the content of this form when the user clicks 'apply' + * @param leftInfo Delegate for handling the left part of the recommendation-pair + * @param rightInfo Delegate for handling the right part of the recommendation-pair + */ + public AbstractPairRecommendationPanel(final User user, IValidator validator, final IRecommendationInfo leftInfo, final IRecommendationInfo rightInfo ) { + this.user = user; + this.validator = validator; + this.leftInfo = leftInfo; + this.rightInfo = rightInfo; + } + + // FIXME: better than copy/pasting the MSG field into every sub-class but not really nice yet. + protected final static FLYSConstants msg() { + return MSG_PROVIDER; + } + + /** + * Remove first occurrence of "[" and "]" (if both do occur). + * @param value String to be stripped of [] (might be null). + * @return input string but with [ and ] removed, or input string if no + * brackets were found. + * @see StringUtil.unbracket + */ + // FIXME: check if this is the same as STringUItils#unbracket + private static final String unbracket(String value) { + // null- guard. + if (value == null) return value; + + int start = value.indexOf("["); + int end = value.indexOf("]"); + + if (start < 0 || end < 0) { + return value; + } + + return value.substring(start + 1, end); + } + + /** + * Create a recommendation from a string representation of it. + * @param from string in format as shown above. + * @param leftInfo2 + * @return recommendation from input string. + */ + private Recommendation createRecommendationFromString(final String from, final IRecommendationInfo info) { + // TODO Construct "real" filter. + String[] parts = unbracket(from).split(";"); + Recommendation.Filter filter = new Recommendation.Filter(); + Recommendation.Facet facet = new Recommendation.Facet( + parts[1], + parts[2]); + + List facets = new ArrayList(); + facets.add(facet); + filter.add("longitudinal_section", facets); + + final String factory = info.getFactory( ); + + final Recommendation r = new Recommendation(factory, parts[0], this.artifact.getUuid(), filter); + r.setDisplayName(parts[3]); + return r; + } + + + /** + * Add RecomendationPairRecords from input String to the ListGrid. + */ + private void populateGridFromString(String from){ + // Split this string. + // Create according recommendations and display strings. + String[] recs = from.split("#"); + if (recs.length % 2 != 0) return; + for (int i = 0; i < recs.length; i+=2) { + Recommendation minuend = + createRecommendationFromString(recs[i+0], leftInfo); + Recommendation subtrahend = + createRecommendationFromString(recs[i+1], rightInfo); + + RecommendationPairRecord pr = new RecommendationPairRecord( + minuend, subtrahend); + // This Recommendation Pair comes from the data string and was thus + // already cloned. + pr.setIsAlreadyLoaded(true); + this.differencesList.addData(pr); + } + } + + /** + * Creates the graphical representation and interaction widgets for the data. + * @param dataList the data. + * @return graphical representation and interaction widgets for data. + */ + @Override + public final Canvas create(DataList dataList) { + + final Canvas widget = createWidget(); + + final Canvas canvas = createChooserWidgets(widget, dataList, user, differencesList); + + populateGrid(dataList); + + return canvas; + } + + /** + * Creates the individual parts of the input-helper area ('Eingabeunterstützung') for choosing the content of this widget. + */ + protected abstract Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User auser, final ListGrid diffList); + + private void populateGrid(DataList dataList) { + Data data = dataList.get(0); + this.dataName = data.getLabel(); + for (int i = 0; i < dataList.size(); i++) { + if (dataList.get(i) != null && dataList.get(i).getItems() != null) { + if (dataList.get(i).getItems() != null) { + populateGridFromString( + dataList.get(i).getItems()[0].getStringValue()); + } + } + } + } + + @Override + public final List validate() { + return validator.validate(differencesList, MSG_PROVIDER); + } + + /** + * Creates layout with grid that displays selection inside. + */ + protected final Canvas createWidget() { + VLayout layout = new VLayout(); + differencesList = new ListGrid(); + + differencesList.setCanEdit(false); + differencesList.setCanSort(false); + differencesList.setShowHeaderContextMenu(false); + differencesList.setHeight(150); + differencesList.setShowAllRecords(true); + + ListGridField nameField = new ListGridField("first", "Minuend"); + ListGridField capitalField = new ListGridField("second", "Subtrahend"); + // Track removed rows, therefore more or less reimplement + // setCanRecomeRecords. + final ListGridField removeField = + new ListGridField("_removeRecord", "Remove Record"){{ + setType(ListGridFieldType.ICON); + setIcon(GWT.getHostPageBaseURL() + msg().removeFeature()); + setCanEdit(false); + setCanFilter(false); + setCanSort(false); + setCanGroupBy(false); + setCanFreeze(false); + setWidth(25); + }}; + + differencesList.setFields(new ListGridField[] {nameField, + capitalField, removeField}); + + differencesList.addRecordClickHandler(new RecordClickHandler() { + @Override + public void onRecordClick(final RecordClickEvent event) { + // Just handle remove-clicks + if(!event.getField().getName().equals(removeField.getName())) { + return; + } + trackRemoved(event.getRecord()); + event.getViewer().removeData(event.getRecord()); + } + }); + layout.addMember(differencesList); + + return layout; + } + + + /** + * Add record to list of removed records. + */ + protected final void trackRemoved(Record r) { + RecommendationPairRecord pr = (RecommendationPairRecord) r; + this.removedPairs.add(pr); + } + + /** + * Validates data, does nothing if invalid, otherwise clones new selected + * waterlevels and add them to collection, forward the artifact. + */ + @Override + public void onClick(ClickEvent e) { + GWT.log("AbstractPairRecommendationPanel.onClick"); + + List errors = validate(); + if (errors != null && !errors.isEmpty()) { + showErrors(errors); + return; + } + + Config config = Config.getInstance(); + String locale = config.getLocale(); + + ListGridRecord[] records = differencesList.getRecords(); + + List ar = new ArrayList(); + List all = new ArrayList(); + + for (ListGridRecord record : records) { + RecommendationPairRecord r = + (RecommendationPairRecord) record; + // Do not add "old" recommendations. + if (!r.isAlreadyLoaded()) { + // Check whether one of those is a dike or similar. + // TODO differentiate and merge: new clones, new, old. + Recommendation firstR = r.getFirst(); + leftInfo.adjustRecommendation(firstR); + + Recommendation secondR = r.getSecond(); + rightInfo.adjustRecommendation(secondR); + ar.add(firstR); + ar.add(secondR); + } + else { + all.add(r.getFirst()); + all.add(r.getSecond()); + } + } + + final Recommendation[] toClone = ar.toArray(new Recommendation[ar.size()]); + final Recommendation[] toUse = all.toArray(new Recommendation[all.size()]); + + // Find out whether "old" artifacts have to be removed. + List artifactIdsToRemove = new ArrayList(); + for (RecommendationPairRecord rp: this.removedPairs) { + Recommendation first = rp.getFirst(); + Recommendation second = rp.getSecond(); + + for (Recommendation recommendation: toUse) { + if (first != null && first.getIDs().equals(recommendation.getIDs())) { + first = null; + } + if (second != null && second.getIDs().equals(recommendation.getIDs())) { + second = null; + } + + if (first == null && second == null) { + break; + } + } + if (first != null) { + artifactIdsToRemove.add(first.getIDs()); + } + if (second != null) { + artifactIdsToRemove.add(second.getIDs()); + } + } + + // Remove old artifacts, if any. Do this asychronously without much + // feedback. + for(final String uuid: artifactIdsToRemove) { + removeArtifactService.remove(this.collection, + uuid, + locale, + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + GWT.log("RemoveArtifact (" + uuid + ") failed."); + } + @Override + public void onSuccess(Collection coll) { + GWT.log("RemoveArtifact succeeded"); + } + }); + } + + // Clone new ones (and spawn statics), go forward. + parameterList.lockUI(); + loadArtifactService.loadMany( + this.collection, + toClone, + //"staticwkms" and "waterlevel" + null, + locale, + new AsyncCallback() { + @Override + public void onFailure(Throwable caught) { + caught.printStackTrace(); + GWT.log("Failure of cloning with factories!"); + parameterList.unlockUI(); + } + @Override + public void onSuccess(Artifact[] artifacts) { + GWT.log("Successfully cloned " + toClone.length + + " with factories."); + + fireStepForwardEvent(new StepForwardEvent( + getData(toClone, artifacts, toUse))); + parameterList.unlockUI(); + } + }); + } + + /** + * Create Data and DataItem from selection (a long string with identifiers + * to construct diff-pairs). + * + * @param newRecommendations "new" recommendations (did not survive a + * backjump). + * @param newArtifacts artifacts cloned from newRecommendations. + * @param oldRecommendations old recommendations that survived a backjump. + * + * @return dataitem with a long string with identifiers to construct + * diff-pairs. + */ + protected final Data[] getData( + Recommendation[] newRecommendations, + Artifact[] newArtifacts, + Recommendation[] oldRecommendations) + { + // Construct string with info about selections. + String dataItemString = ""; + for (int i = 0; i < newRecommendations.length; i++) { + Recommendation r = newRecommendations[i]; + Artifact newArtifact = newArtifacts[i]; + String uuid = newArtifact.getUuid(); + r.setMasterArtifact(uuid); + + if (i>0) + dataItemString += "#"; + + // REMARK: ugly, but we know that the recommandations comes in left/right pairs. + final IRecommendationInfo info = i % 2 == 0 ? leftInfo : rightInfo; + + dataItemString += createDataString(uuid, r, info); + } + + for (int i = 0; i < oldRecommendations.length; i++) { + Recommendation r = oldRecommendations[i]; + String uuid = r.getIDs(); + + if (dataItemString.length() > 0) + dataItemString += "#"; + + // REMARK: ugly, but we know that the recommandations comes in left/right pairs. + final IRecommendationInfo info = i % 2 == 0 ? leftInfo : rightInfo; + + dataItemString += createDataString(uuid, r, info); + } + + // TODO some hassle could be resolved by using multiple DataItems + // (e.g. one per pair). + DataItem item = new DefaultDataItem(dataName, dataName, dataItemString); + return new Data[] { new DefaultData( + dataName, null, null, new DataItem[] {item}) }; + } + + /** + * Creates part of the String that encodes minuend or subtrahend. + * @param recommendation Recommendation to wrap in string. + * @param info Provides the factory to encode. + */ + protected static final String createDataString(final String artifactUuid, final Recommendation recommendation, final IRecommendationInfo info) { + final String factory = info.getDataStringFactory(); + + Filter filter = recommendation.getFilter(); + Facet f = null; + + if(filter != null) { + Map> outs = filter.getOuts(); + Set>> entries = outs.entrySet(); + + for (Map.Entry> entry: entries) { + List fs = entry.getValue(); + + f = fs.get(0); + if (f != null) { + break; + } + } + + return "[" + artifactUuid + ";" + + f.getName() + + ";" + + f.getIndex() + + ";" + + recommendation.getDisplayName() + "]"; + } + + return "[" + + artifactUuid + + ";" + factory + ";0;" + + recommendation.getDisplayName() + "]"; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/AbstractUIProvider.java Fri Jan 19 11:23:42 2018 +0100 @@ -309,12 +309,14 @@ return null; } - + /** + * Validates the selection. + * @return List of internationalized errror messages (if any). + */ public List validate() { return new ArrayList(); // FIXME: What's this? } - /** Create simple DefaultData with single DataItem inside. */ public static DefaultData createDataArray(String name, String value) { DataItem item = new DefaultDataItem( diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/CollectionView.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/CollectionView.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/CollectionView.java Fri Jan 19 11:23:42 2018 +0100 @@ -199,6 +199,9 @@ this.parameterList = new ParameterList( flys, this, + // FIXME: literally every information about the artifact is transported from the server side + // but... the international name is resolved client-side.... Instead also transport the description of the artifact and use it! + // FIXME: the same holds for a very few other international strings (e.g. names of facets used in Tabs) messages.getString(artifact.getName()), artifact); } diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePairWidget.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePairWidget.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacagePairWidget.java Fri Jan 19 11:23:42 2018 +0100 @@ -49,12 +49,14 @@ * * @param artifact Artifact to query datacage with. * @param user User to query datacage with. - * @param outs outs to query datacage with. + * @param leftOuts outs to query the left datacage with. + * @param rightOuts outs to query the right datacage with. * @param grid Grid into which to insert selection of pairs. */ public DatacagePairWidget(Artifact artifact, User user, - String outs, + String leftOuts, + String rightOuts, ListGrid grid) { this.grid = grid; @@ -62,13 +64,13 @@ firstDatacageWidget = new DatacageWidget( artifact, user, - outs, + leftOuts, "load-system:true", false); secondDatacageWidget = new DatacageWidget( artifact, user, - outs, + rightOuts, "load-system:true", false); firstDatacageWidget.setIsMutliSelectable(false); diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DatacageTwinPanel.java Fri Jan 19 11:23:42 2018 +0100 @@ -8,531 +8,56 @@ package org.dive4elements.river.client.client.ui; +import org.dive4elements.river.client.shared.model.DataList; +import org.dive4elements.river.client.shared.model.User; + import com.google.gwt.core.client.GWT; -import com.google.gwt.user.client.rpc.AsyncCallback; - -import com.smartgwt.client.data.Record; -import com.smartgwt.client.types.ListGridFieldType; import com.smartgwt.client.widgets.Canvas; -import com.smartgwt.client.widgets.events.ClickEvent; import com.smartgwt.client.widgets.grid.ListGrid; -import com.smartgwt.client.widgets.grid.ListGridField; -import com.smartgwt.client.widgets.grid.ListGridRecord; -import com.smartgwt.client.widgets.grid.events.RecordClickEvent; -import com.smartgwt.client.widgets.grid.events.RecordClickHandler; import com.smartgwt.client.widgets.layout.HLayout; import com.smartgwt.client.widgets.layout.VLayout; -import org.dive4elements.river.client.client.Config; -import org.dive4elements.river.client.client.FLYSConstants; -import org.dive4elements.river.client.client.event.StepForwardEvent; -import org.dive4elements.river.client.client.services.LoadArtifactServiceAsync; -import org.dive4elements.river.client.client.services.RemoveArtifactServiceAsync; -import org.dive4elements.river.client.shared.model.Artifact; -import org.dive4elements.river.client.shared.model.Collection; -import org.dive4elements.river.client.shared.model.Data; -import org.dive4elements.river.client.shared.model.DataItem; -import org.dive4elements.river.client.shared.model.DataList; -import org.dive4elements.river.client.shared.model.DefaultData; -import org.dive4elements.river.client.shared.model.DefaultDataItem; -import org.dive4elements.river.client.shared.model.Recommendation; -import org.dive4elements.river.client.shared.model.Recommendation.Facet; -import org.dive4elements.river.client.shared.model.Recommendation.Filter; -import org.dive4elements.river.client.shared.model.User; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - -// TODO Probably better to branch off AbstractUIProvider. -// TODO Merge with other datacage-widget impls. /** - * Panel containing a Grid and a "next" button. The Grid is fed by a + * A {@link AbstractPairRecommendationPanel} that uses a 'TwinDatacage' in the help-input area. * DatacagePairWidget which is put in the input-helper area. */ -public class DatacageTwinPanel -extends TextProvider { - - private static final long serialVersionUID = 8906629596491827857L; - - protected static FLYSConstants MSG = GWT.create(FLYSConstants.class); - - protected String dataName; - - protected User user; - - /** ListGrid that displays user-selected pairs to build differences with. */ - protected ListGrid differencesList; - - /** - * List to track previously selected but now removed pairs. (Needed to - * be able to identify artifacts that can be removed from the collection. - */ - protected List removedPairs = - new ArrayList(); - - /** Service handle to clone and add artifacts to collection. */ - LoadArtifactServiceAsync loadArtifactService = GWT.create( - org.dive4elements.river.client.client.services - .LoadArtifactService.class); - - /** Service to remove artifacts from collection. */ - RemoveArtifactServiceAsync removeArtifactService = GWT.create( - org.dive4elements.river.client.client.services - .RemoveArtifactService.class); - - - public DatacageTwinPanel(User user) { - super(); - this.user = user; - } - - - /** - * Remove first occurrence of "[" and "]" (if both do occur). - * @param value String to be stripped of [] (might be null). - * @return input string but with [ and ] removed, or input string if no - * brackets were found. - * @see StringUtil.unbracket - */ - public static final String unbracket(String value) { - // null- guard. - if (value == null) return value; - - int start = value.indexOf("["); - int end = value.indexOf("]"); - - if (start < 0 || end < 0) { - return value; - } - - value = value.substring(start + 1, end); +public abstract class DatacageTwinPanel +extends AbstractPairRecommendationPanel { - return value; - } - - - /** - * Create a recommendation from a string representation of it. - * @param from string in format as shown above. - * @return recommendation from input string. - */ - public Recommendation createRecommendationFromString( - String from, - String factory - ) { - // TODO Construct "real" filter. - String[] parts = unbracket(from).split(";"); - Recommendation.Filter filter = new Recommendation.Filter(); - Recommendation.Facet facet = new Recommendation.Facet( - parts[1], - parts[2]); - - List facets = new ArrayList - (); - facets.add(facet); - filter.add("longitudinal_section", facets); - Recommendation r = new Recommendation(factory, parts[0], - this.artifact.getUuid(), filter); - r.setDisplayName(parts[3]); - return r; - } - + private IDatacageTwinPanelInfo leftInfo; + private IDatacageTwinPanelInfo rightInfo; - /** - * Add RecomendationPairRecords from input String to the ListGrid. - */ - public void populateGridFromString(String from, String factory){ - // Split this string. - // Create according recommendations and display strings. - String[] recs = from.split("#"); - if (recs.length % 2 != 0) return; - for (int i = 0; i < recs.length; i+=2) { - Recommendation minuend = - createRecommendationFromString(recs[i+0], factory); - Recommendation subtrahend = - createRecommendationFromString(recs[i+1], factory); + public static interface IDatacageTwinPanelInfo extends IRecommendationInfo + { + String getOuts(); + } + + public DatacageTwinPanel(final User user, IValidator validator, final IDatacageTwinPanelInfo leftInfo, final IDatacageTwinPanelInfo rightInfo ) { + super(user, validator, leftInfo, rightInfo); - RecommendationPairRecord pr = new RecommendationPairRecord( - minuend, subtrahend); - // This Recommendation Pair comes from the data string and was thus - // already cloned. - pr.setIsAlreadyLoaded(true); - this.differencesList.addData(pr); - } - } - - - /** - * Creates the graphical representation and interaction widgets - * for the data. - * @param dataList the data. - * @return graphical representation and interaction widgets for data. - */ + this.leftInfo = leftInfo; + this.rightInfo = rightInfo; + } + @Override - public Canvas create(DataList dataList) { + protected final Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User user, final ListGrid differencesList) { GWT.log("createData()"); - Canvas widget = createWidget(); Canvas submit = getNextButton(); VLayout layout = new VLayout(); HLayout helperLayout = new HLayout(); - helperLayout.addMember(new DatacagePairWidget(this.artifact, - user, "winfo_diff_twin_panel", differencesList)); + + final String leftOuts = leftInfo.getOuts(); + final String rightOuts = rightInfo.getOuts(); + + helperLayout.addMember(new DatacagePairWidget(this.artifact, user, leftOuts, rightOuts, differencesList)); layout.addMember(widget); layout.addMember(submit); layout.setMembersMargin(10); this.helperContainer.addMember(helperLayout); - populateGrid(dataList, "waterlevel"); - return layout; - } - - protected void populateGrid(DataList dataList, String factory) { - Data data = dataList.get(0); - this.dataName = data.getLabel(); - for (int i = 0; i < dataList.size(); i++) { - if (dataList.get(i) != null - && dataList.get(i).getItems() != null - ) { - if (dataList.get(i).getItems() != null) { - populateGridFromString( - dataList.get(i).getItems()[0].getStringValue(), - factory); - } - } - } - } - - - /** - * Validates the selection. - * @return List of internationalized errror messages (if any). - */ - @Override - public List validate() { - List errors = new ArrayList(); - if (differencesList.getRecords().length == 0) { - errors.add(MSG.error_no_waterlevel_pair_selected()); - } - // Check whether minuend and subtrahend are equal. - for (ListGridRecord record: differencesList.getRecords()) { - RecommendationPairRecord r = (RecommendationPairRecord) record; - if (r.getFirst().equals(r.getSecond())) { - errors.add(MSG.error_same_waterlevels_in_pair()); - } - } - - return errors; - } - - - /** - * Creates layout with grid that displays selection inside. - */ - public Canvas createWidget() { - VLayout layout = new VLayout(); - differencesList = new ListGrid(); - - differencesList.setCanEdit(false); - differencesList.setCanSort(false); - differencesList.setShowHeaderContextMenu(false); - differencesList.setHeight(150); - differencesList.setShowAllRecords(true); - - ListGridField nameField = new ListGridField("first", "Minuend"); - ListGridField capitalField = new ListGridField("second", "Subtrahend"); - // Track removed rows, therefore more or less reimplement - // setCanRecomeRecords. - final ListGridField removeField = - new ListGridField("_removeRecord", "Remove Record"){{ - setType(ListGridFieldType.ICON); - setIcon(GWT.getHostPageBaseURL() + MSG.removeFeature()); - setCanEdit(false); - setCanFilter(false); - setCanSort(false); - setCanGroupBy(false); - setCanFreeze(false); - setWidth(25); - }}; - - differencesList.setFields(new ListGridField[] {nameField, - capitalField, removeField}); - - differencesList.addRecordClickHandler(new RecordClickHandler() { - @Override - public void onRecordClick(final RecordClickEvent event) { - // Just handle remove-clicks - if(!event.getField().getName() - .equals(removeField.getName()) - ) { - return; - } - trackRemoved(event.getRecord()); - event.getViewer().removeData(event.getRecord()); - } - }); - layout.addMember(differencesList); - return layout; } - - - /** - * Add record to list of removed records. - */ - public void trackRemoved(Record r) { - RecommendationPairRecord pr = (RecommendationPairRecord) r; - this.removedPairs.add(pr); - } - - /** - * Set factory of recommendation such that the correct artifacts will - * be cloned for difference calculations. - */ - public void adjustRecommendation(Recommendation recommendation) { - // XXX: THIS IS AN EVIL HACK TO MAKE W-DIFFERENCES WORK AGAIN! - // TODO: Throw all this code away and do it with server side - // recommendations! - recommendation.setTargetOut("w_differences"); - - if (recommendation.getIDs() != null) { - GWT.log("Setting staticwkms factory for rec with ID " - + recommendation.getIDs()); - recommendation.setFactory("staticwkms"); - } - /* - // So far, we do not need to rewrite the factory anymore, - // except for staticwkms; probably other cases will pop up later. - else if (recommendation.getFactory().equals("winfo")) { - GWT.log("Setting waterlevel factory for a winfo rec."); - recommendation.setFactory("waterlevel"); - } - */ - else { - GWT.log("Leave rec. id " + recommendation.getIDs() + ", factory " - + recommendation.getFactory() + " untouched."); - } - } - - /** - * Validates data, does nothing if invalid, otherwise clones new selected - * waterlevels and add them to collection, forward the artifact. - */ - @Override - public void onClick(ClickEvent e) { - GWT.log("DatacageTwinPanel.onClick"); - - List errors = validate(); - if (errors != null && !errors.isEmpty()) { - showErrors(errors); - return; - } - - Config config = Config.getInstance(); - String locale = config.getLocale(); - - ListGridRecord[] records = differencesList.getRecords(); - - List ar = new ArrayList(); - List all = new ArrayList(); - - for (ListGridRecord record : records) { - RecommendationPairRecord r = - (RecommendationPairRecord) record; - // Do not add "old" recommendations. - if (!r.isAlreadyLoaded()) { - // Check whether one of those is a dike or similar. - // TODO differentiate and merge: new clones, new, old. - Recommendation firstR = r.getFirst(); - adjustRecommendation(firstR); - - Recommendation secondR = r.getSecond(); - adjustRecommendation(secondR); - ar.add(firstR); - ar.add(secondR); - } - else { - all.add(r.getFirst()); - all.add(r.getSecond()); - } - } - - final Recommendation[] toClone = ar.toArray( - new Recommendation[ar.size()]); - final Recommendation[] toUse = all.toArray( - new Recommendation[all.size()]); - - // Find out whether "old" artifacts have to be removed. - List artifactIdsToRemove = new ArrayList(); - for (RecommendationPairRecord rp: this.removedPairs) { - Recommendation first = rp.getFirst(); - Recommendation second = rp.getSecond(); - - for (Recommendation recommendation: toUse) { - if (first != null - && first.getIDs().equals(recommendation.getIDs()) - ) { - first = null; - } - if (second != null - && second.getIDs().equals(recommendation.getIDs()) - ) { - second = null; - } - - if (first == null && second == null) { - break; - } - } - if (first != null) { - artifactIdsToRemove.add(first.getIDs()); - } - if (second != null) { - artifactIdsToRemove.add(second.getIDs()); - } - } - - // Remove old artifacts, if any. Do this asychronously without much - // feedback. - for(final String uuid: artifactIdsToRemove) { - removeArtifactService.remove(this.collection, - uuid, - locale, - new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - GWT.log("RemoveArtifact (" + uuid + ") failed."); - } - @Override - public void onSuccess(Collection collection) { - GWT.log("RemoveArtifact succeeded"); - } - }); - } - - // Clone new ones (and spawn statics), go forward. - parameterList.lockUI(); - loadArtifactService.loadMany( - this.collection, - toClone, - //"staticwkms" and "waterlevel" - null, - locale, - new AsyncCallback() { - @Override - public void onFailure(Throwable caught) { - GWT.log("Failure of cloning with factories!"); - parameterList.unlockUI(); - } - @Override - public void onSuccess(Artifact[] artifacts) { - GWT.log("Successfully cloned " + toClone.length + - " with factories."); - - fireStepForwardEvent(new StepForwardEvent( - getData(toClone, artifacts, toUse))); - parameterList.unlockUI(); - } - }); - } - - - /** - * Create Data and DataItem from selection (a long string with identifiers - * to construct diff-pairs). - * - * @param newRecommendations "new" recommendations (did not survive a - * backjump). - * @param newArtifacts artifacts cloned from newRecommendations. - * @param oldRecommendations old recommendations that survived a backjump. - * - * @return dataitem with a long string with identifiers to construct - * diff-pairs. - */ - protected Data[] getData( - Recommendation[] newRecommendations, - Artifact[] newArtifacts, - Recommendation[] oldRecommendations) - { - // Construct string with info about selections. - String dataItemString = ""; - for (int i = 0; i < newRecommendations.length; i++) { - Recommendation r = newRecommendations[i]; - Artifact newArtifact = newArtifacts[i]; - String uuid = newArtifact.getUuid(); - r.setMasterArtifact(uuid); - if (i>0) dataItemString += "#"; - - dataItemString += createDataString(uuid, r); - } - - for (int i = 0; i < oldRecommendations.length; i++) { - Recommendation r = oldRecommendations[i]; - String uuid = r.getIDs(); - if (dataItemString.length() > 0) dataItemString += "#"; - - dataItemString += createDataString(uuid, r); - } - - // TODO some hassle could be resolved by using multiple DataItems - // (e.g. one per pair). - DataItem item = new DefaultDataItem(dataName, dataName, dataItemString); - return new Data[] { new DefaultData( - dataName, null, null, new DataItem[] {item}) }; - } - - - protected String createDataString( - String artifact, - Recommendation recommendation - ) { - return createDataString(artifact, recommendation, "staticwkms"); - } - - /** - * Creates part of the String that encodes minuend or subtrahend. - * @param artifact Artifacts UUID. - * @param recommendation Recommendation to wrap in string. - * @param factory The factory to encode. - */ - protected String createDataString( - String artifact, - Recommendation recommendation, - String factory) - { - Filter filter = recommendation.getFilter(); - Facet f = null; - - if(filter != null) { - Map> outs = filter.getOuts(); - Set>> entries = outs.entrySet(); - - for (Map.Entry> entry: entries) { - List fs = entry.getValue(); - - f = fs.get(0); - if (f != null) { - break; - } - } - - return "[" + artifact + ";" - + f.getName() - + ";" - + f.getIndex() - + ";" - + recommendation.getDisplayName() + "]"; - } - else { - return "[" - + artifact - + ";" + factory + ";0;" - + recommendation.getDisplayName() + "]"; - } - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DefaultDatacageTwinPanelInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/DefaultDatacageTwinPanelInfo.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,47 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.client.client.ui; + +import org.dive4elements.river.client.client.ui.DatacageTwinPanel.IDatacageTwinPanelInfo; +import org.dive4elements.river.client.shared.model.Recommendation; + +/** + * @author Gernot Belger + */ +public final class DefaultDatacageTwinPanelInfo implements IDatacageTwinPanelInfo { + + private String factory; + private String outs; + + public DefaultDatacageTwinPanelInfo(final String factory, final String outs) { + this.factory = factory; + this.outs = outs; + } + + @Override + public String getFactory() { + return factory; + } + + @Override + public String getDataStringFactory() { + return factory; + } + + @Override + public void adjustRecommendation(Recommendation recommendation) { + recommendation.setFactory(factory); + } + + @Override + public String getOuts() { + return outs; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ParameterList.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ParameterList.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/ParameterList.java Fri Jan 19 11:23:42 2018 +0100 @@ -65,6 +65,7 @@ import org.dive4elements.river.client.shared.model.OutputMode; import org.dive4elements.river.client.shared.model.ReportMode; import org.dive4elements.river.client.shared.model.River; +import org.dive4elements.river.client.shared.model.SINFOArtifact; import org.dive4elements.river.client.shared.model.WINFOArtifact; import java.util.ArrayList; @@ -771,8 +772,11 @@ setCurrentData(null, null); } } + + // FIXME: we got a whole artifact framework to separate ui and backend stuff, but in the end.... we have switches over specific datatypes here... if (art instanceof WINFOArtifact - || art instanceof FixAnalysisArtifact) { + || art instanceof SINFOArtifact + || art instanceof FixAnalysisArtifact) { createGaugePanel(); renderInfo(desc.getRiver(), desc.getOldData()); } diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/UIProviderFactory.java Fri Jan 19 11:23:42 2018 +0100 @@ -22,6 +22,7 @@ import org.dive4elements.river.client.client.ui.minfo.SedLoadEpochPanel; import org.dive4elements.river.client.client.ui.minfo.SedLoadPeriodPanel; import org.dive4elements.river.client.client.ui.minfo.SedLoadSQTiPanel; +import org.dive4elements.river.client.client.ui.sinfo.FlowDepthTwinPanel; import org.dive4elements.river.client.client.ui.sq.SQPeriodPanel; import org.dive4elements.river.client.shared.model.User; @@ -86,8 +87,8 @@ else if (uiProvider.equals("dgm_datacage_panel")) { return new DemDatacagePanel(user); } - else if (uiProvider.equals("datacage_twin_panel")) { - return new DatacageTwinPanel(user); + else if (uiProvider.equals("waterlevel_twin_panel")) { + return new WaterlevelTwinPanel(user); } else if (uiProvider.equals("auto_integer")) { return new AutoIntegerPanel(); @@ -194,10 +195,12 @@ else if (uiProvider.equals("static_sqrelation")) { return new StaticDataPanel(); } - else { - //GWT.log("Picked default provider."); - return new SelectProvider(); - } + + if ("sinfo_flowdepth_twin_panel".equals(uiProvider)) + return new FlowDepthTwinPanel(user); + + //GWT.log("Picked default provider."); + return new SelectProvider(); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelRecommandationInfo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelRecommandationInfo.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,69 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.client.client.ui; + +import org.dive4elements.river.client.client.ui.DatacageTwinPanel.IDatacageTwinPanelInfo; +import org.dive4elements.river.client.shared.model.Recommendation; + +import com.google.gwt.core.client.GWT; + +/** + * @author Gernot Belger + */ +public final class WaterlevelRecommandationInfo implements IDatacageTwinPanelInfo { + + private String outs; + + public WaterlevelRecommandationInfo(String outs ) { + this.outs = outs; + } + + @Override + public String getFactory() { + // FIXME: why are the factory here and the one used in createDataString different? + // Probably also because of the 'throw all this code away comment' + return "waterlevel"; + } + + @Override + public String getDataStringFactory() { + return "staticwkms"; + } + + @Override + public void adjustRecommendation(Recommendation recommendation) { + // XXX: THIS IS AN EVIL HACK TO MAKE W-DIFFERENCES WORK AGAIN! + // TODO: Throw all this code away and do it with server side recommendations! + recommendation.setTargetOut("w_differences"); + + if (recommendation.getIDs() != null) { + GWT.log("Setting staticwkms factory for rec with ID " + + recommendation.getIDs()); + recommendation.setFactory("staticwkms"); + } + /* + // So far, we do not need to rewrite the factory anymore, + // except for staticwkms; probably other cases will pop up later. + else if (recommendation.getFactory().equals("winfo")) { + GWT.log("Setting waterlevel factory for a winfo rec."); + recommendation.setFactory("waterlevel"); + } + */ + else { + GWT.log("Leave rec. id " + recommendation.getIDs() + ", factory " + + recommendation.getFactory() + " untouched."); + } + } + + @Override + public String getOuts() { + return outs; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanel.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,25 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.client.client.ui; + +import org.dive4elements.river.client.shared.model.User; + +/** + * A DatacageTwinPanel implementation for W-INFO Differences: choose two waterlevels + * + * @author Gernot Belger + */ +public class WaterlevelTwinPanel +extends DatacageTwinPanel { + + public WaterlevelTwinPanel(final User user) { + super(user, new WaterlevelTwinPanelValidator(), new WaterlevelRecommandationInfo("winfo_diff_twin_panel"), new WaterlevelRecommandationInfo("winfo_diff_twin_panel") ); + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanelValidator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/WaterlevelTwinPanelValidator.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,48 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.client.client.ui; + +import java.util.ArrayList; +import java.util.List; + +import org.dive4elements.river.client.client.FLYSConstants; +import org.dive4elements.river.client.client.ui.AbstractPairRecommendationPanel.IValidator; + +import com.smartgwt.client.widgets.grid.ListGrid; +import com.smartgwt.client.widgets.grid.ListGridRecord; + +/** + * Contains the old code from the validate-method of the DatacageTwinPanel. + * + * @author Gernot Belger + */ +public final class WaterlevelTwinPanelValidator implements IValidator { + + @Override + public List validate(final ListGrid differencesList, final FLYSConstants msgProvider) { + + final List errors = new ArrayList(); + if (differencesList.getRecords().length == 0) { + // FIXME: waterlevel dependent! This will lead to a bad error message in English, for M-Info/Bed-Differences calculation + errors.add(msgProvider.error_no_waterlevel_pair_selected()); + } + // Check whether minuend and subtrahend are equal. + for (ListGridRecord record: differencesList.getRecords()) { + RecommendationPairRecord r = (RecommendationPairRecord) record; + if (r.getFirst().equals(r.getSecond())) { + // FIXME: this is still waterlevel specific! + // TODO: delegate validation to specific implementations + errors.add(msgProvider.error_same_waterlevels_in_pair()); + } + } + + return errors; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/minfo/BedHeightsDatacagePanel.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/minfo/BedHeightsDatacagePanel.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/minfo/BedHeightsDatacagePanel.java Fri Jan 19 11:23:42 2018 +0100 @@ -8,85 +8,51 @@ package org.dive4elements.river.client.client.ui.minfo; +import java.util.List; + +import org.dive4elements.river.client.client.ui.AbstractPairRecommendationPanel; +import org.dive4elements.river.client.client.ui.DatacageWidget; +import org.dive4elements.river.client.client.ui.DefaultDatacageTwinPanelInfo; +import org.dive4elements.river.client.client.ui.RecommendationPairRecord; +import org.dive4elements.river.client.client.ui.WaterlevelTwinPanelValidator; +import org.dive4elements.river.client.shared.model.DataList; +import org.dive4elements.river.client.shared.model.ToLoad; +import org.dive4elements.river.client.shared.model.User; + import com.google.gwt.core.client.GWT; - import com.smartgwt.client.util.SC; import com.smartgwt.client.widgets.Button; import com.smartgwt.client.widgets.Canvas; - import com.smartgwt.client.widgets.events.ClickEvent; import com.smartgwt.client.widgets.events.ClickHandler; - +import com.smartgwt.client.widgets.grid.ListGrid; import com.smartgwt.client.widgets.layout.VLayout; import com.smartgwt.client.widgets.tree.TreeNode; -import org.dive4elements.river.client.client.FLYSConstants; - -import org.dive4elements.river.client.client.services.LoadArtifactServiceAsync; -import org.dive4elements.river.client.client.services.RemoveArtifactServiceAsync; - -import org.dive4elements.river.client.client.ui.DatacageTwinPanel; -import org.dive4elements.river.client.client.ui.DatacageWidget; -import org.dive4elements.river.client.client.ui.RecommendationPairRecord; - -import org.dive4elements.river.client.shared.model.DataList; -import org.dive4elements.river.client.shared.model.ToLoad; - -import org.dive4elements.river.client.shared.model.Recommendation; -import org.dive4elements.river.client.shared.model.User; - -import java.util.ArrayList; -import java.util.List; - -// TODO Probably better to branch off AbstractUIProvider. public class BedHeightsDatacagePanel -extends DatacageTwinPanel { - - protected static FLYSConstants MSG = GWT.create(FLYSConstants.class); - - /** - * List to track previously selected but now removed pairs. (Needed to - * be able to identify artifacts that can be removed from the collection. - */ - protected List removedPairs = - new ArrayList(); - - /** Service handle to clone and add artifacts to collection. */ - LoadArtifactServiceAsync loadArtifactService = GWT.create( - org.dive4elements.river.client.client.services - .LoadArtifactService.class); - - /** Service to remove artifacts from collection. */ - RemoveArtifactServiceAsync removeArtifactService = GWT.create( - org.dive4elements.river.client.client.services - .RemoveArtifactService.class); - - protected DatacageWidget datacage; +extends AbstractPairRecommendationPanel { public BedHeightsDatacagePanel(User user) { - super(user); + // FIXME: This will lead to a bad error message in English (i.e. contains something about waterlevels), for M-Info/Bed-Differences calculation + // BUT: this is the behavior of 3.2.1 (because of sloppy derivation), so we do not change it now + super(user, new WaterlevelTwinPanelValidator(), new DefaultDatacageTwinPanelInfo("bedheight", null), new DefaultDatacageTwinPanelInfo("bedheight", null) ); } - /** - * Creates graphical representation and interaction widgets for the data. - * @param dataList the data. - * @return graphical representation and interaction widgets for data. - */ @Override - public Canvas create(DataList dataList) { + protected Canvas createChooserWidgets(final Canvas widget, final DataList dataList, final User user, final ListGrid differencesList) { GWT.log("createData()"); - Canvas widget = createWidget(); Canvas submit = getNextButton(); - datacage = new DatacageWidget( + + final DatacageWidget datacage = new DatacageWidget( this.artifact, user, "minfo_diff_panel", "load-system:true", false); - Button plusBtn = new Button(MSG.datacage_add_pair()); + Button plusBtn = new Button(msg().datacage_add_pair()); plusBtn.setAutoFit(true); plusBtn.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { - plusClicked(); + plusClicked(datacage, differencesList); } }); @@ -100,32 +66,19 @@ layout.setMembersMargin(10); this.helperContainer.addMember(helperLayout); - populateGrid(dataList, "bedheight"); - return layout; } - public void adjustRecommendation(Recommendation recommendation) { - recommendation.setFactory("bedheight"); - } - - @Override - protected String createDataString( - String artifact, - Recommendation recommendation - ) { - return createDataString(artifact, recommendation, "bedheight"); - } - /** * Callback for add-button. * Fires to load for every selected element and handler. + * @param differencesList */ - public void plusClicked() { + protected final static void plusClicked( final DatacageWidget datacage, ListGrid differencesList ) { List selection = datacage.getPlainSelection(); if (selection == null || selection.isEmpty()) { - SC.say(MSG.warning()); + SC.say(msg().warning()); return; } diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanel.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanel.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,25 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.client.client.ui.sinfo; + +import org.dive4elements.river.client.client.ui.DatacageTwinPanel; +import org.dive4elements.river.client.client.ui.DefaultDatacageTwinPanelInfo; +import org.dive4elements.river.client.client.ui.WaterlevelRecommandationInfo; +import org.dive4elements.river.client.shared.model.User; + +/** + * @author Gernot Belger + */ +public class FlowDepthTwinPanel +extends DatacageTwinPanel { + public FlowDepthTwinPanel(final User user) { + super(user, new FlowDepthTwinPanelValidator(), new WaterlevelRecommandationInfo("sinfo_flowdepth_waterlevels"), new DefaultDatacageTwinPanelInfo("bedheight", "sinfo_flowdepth_minfo_heights") ); + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanelValidator.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/sinfo/FlowDepthTwinPanelValidator.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,39 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.client.client.ui.sinfo; + +import java.util.ArrayList; +import java.util.List; + +import org.dive4elements.river.client.client.FLYSConstants; +import org.dive4elements.river.client.client.ui.AbstractPairRecommendationPanel.IValidator; + +import com.smartgwt.client.widgets.grid.ListGrid; +import com.smartgwt.client.widgets.grid.ListGridRecord; + +/** + * Contains the old code from the validate-method of the DatacageTwinPanel. + * + * @author Gernot Belger + */ +final class FlowDepthTwinPanelValidator implements IValidator { + + @Override + public List validate(final ListGrid differencesList, final FLYSConstants msgProvider) { + + final List errors = new ArrayList(); + if (differencesList.getRecords().length == 0) { + // FIXME: waterlevel dependent! This will lead to a bad error message in English, for M-Info/Bed-Differences calculation + errors.add(msgProvider.sinfo_flowdepth_twinpanel_no_pair_selected()); + } + + return errors; + } +} \ No newline at end of file diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/server/FLYSArtifactCreator.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/FLYSArtifactCreator.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/FLYSArtifactCreator.java Fri Jan 19 11:23:42 2018 +0100 @@ -31,6 +31,7 @@ import org.dive4elements.river.client.shared.model.FixAnalysisArtifact; import org.dive4elements.river.client.shared.model.GaugeDischargeCurveArtifact; import org.dive4elements.river.client.shared.model.MapArtifact; +import org.dive4elements.river.client.shared.model.SINFOArtifact; import org.dive4elements.river.client.shared.model.MINFOArtifact; import org.dive4elements.river.client.shared.model.StaticSQRelationArtifact; import org.dive4elements.river.client.shared.model.WINFOArtifact; @@ -134,35 +135,47 @@ name = name.trim(); - if (name.length() > 0 && name.equals("winfo")) { + // FIXME: why do we have a super sophisticated artifact-framework if, in the end, module dependent stuff is still switched manually.... + if (name.equals("winfo")) { log.debug("+++++ NEW WINFO ARTIFACT."); return new WINFOArtifact(uuid, hash, background, msg); } - else if (name.length() > 0 && name.equals("new_map")) { + + if (name.equals("new_map")) { log.debug("+++++ NEW MAP ARTIFACT."); return new MapArtifact(uuid, hash, background, msg); } - else if (name.length() > 0 && name.equals("new_chart")) { + + if (name.equals("new_chart")) { log.debug("+++++ NEW CHART ARTIFACT."); return new ChartArtifact(uuid, hash, background, msg); } - else if (name.length() > 0 && name.equals("minfo")) { + + if (name.equals("minfo")) { log.debug("+++++ NEW MINFO ARTIFACT."); return new MINFOArtifact(uuid, hash, background, msg); } - else if (name.length() > 0 && name.equals("fixanalysis")) { + + if (name.equals("fixanalysis")) { log.debug("+++++ NEW FIXANALYSIS ARTIFACT."); return new FixAnalysisArtifact(uuid, hash, background, msg); } - else if (name.length() > 0 && name.equals("gaugedischargecurve")) { + + if (name.equals("gaugedischargecurve")) { log.debug("+++++ NEW GAUGEDISCHARGECURVE ARTIFACT."); return new GaugeDischargeCurveArtifact(uuid, hash, background, msg); } - else if (name.length() > 0 && name.equals("staticsqrelation")) { + + if (name.equals("staticsqrelation")) { log.debug("+++++ STATICSQRELATION ARTIFACT."); return new StaticSQRelationArtifact(uuid, hash, background, msg); } + if (name.equals("sinfo")) { + log.debug("+++++ NEW SINFO ARTIFACT."); + return new SINFOArtifact(uuid, hash, background, msg); + } + return new DefaultArtifact(uuid, hash, background, msg); } diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/server/auth/UserClient.java --- a/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/UserClient.java Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/auth/UserClient.java Fri Jan 19 11:23:42 2018 +0100 @@ -84,6 +84,8 @@ account.setAttribute("name", user.getAccount()); //TODO create roles + // FIXME: not creating the roles will write an broken xmldocument (only header) into the artifacts db + // which in turn will result in an exception (which is handled) artuser.appendChild(account); action.appendChild(type); action.appendChild(artuser); diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/java/org/dive4elements/river/client/shared/model/SINFOArtifact.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/SINFOArtifact.java Fri Jan 19 11:23:42 2018 +0100 @@ -0,0 +1,46 @@ +/* Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.client.shared.model; + +import java.util.List; + + +/** + * The SINFO implementation of an Artifact. + * + * @author Gernot Belger + */ +public class SINFOArtifact extends DefaultArtifact { + + /** The name of this artifact: 'sinfo'.*/ + private static final String NAME = "sinfo"; + + /** Necessary for serialization */ + public SINFOArtifact() { + } + +// public SINFOArtifact(String uuid, String hash) { +// super(uuid, hash); +// } + + public SINFOArtifact( + String uuid, + String hash, + boolean inBackground, + List messages + ) { + super(uuid, hash, inBackground, messages); + } + + + public String getName() { + return NAME; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/webapp/WEB-INF/features.xml --- a/gwt-client/src/main/webapp/WEB-INF/features.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/webapp/WEB-INF/features.xml Fri Jan 19 11:23:42 2018 +0100 @@ -1,6 +1,7 @@ + module:sinfo module:winfo module:minfo module:new_map diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/webapp/WEB-INF/log4j.properties --- a/gwt-client/src/main/webapp/WEB-INF/log4j.properties Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/webapp/WEB-INF/log4j.properties Fri Jan 19 11:23:42 2018 +0100 @@ -1,18 +1,15 @@ log4j.rootLogger=DEBUG, FLYS ########## INTERNAL PACKAGES -log4j.category.de.intevation.flys.client.server=DEBUG - +log4j.category.org.dive4elements.river.client.server=DEBUG ########## EXTERNAL PACKAGES log4j.category.org.apache.http=ERROR -log4j.category.de.intevation.artifacts.httpclient=WARN +log4j.category.org.dive4elements.artifacts.httpclient=WARN ########## APPENDER SETTINGS log4j.appender.FLYS.layout=org.apache.log4j.PatternLayout log4j.appender.FLYS.layout.ConversionPattern=%d [%t] %-5p %c - %m%n -log4j.appender.FLYS=org.apache.log4j.RollingFileAppender -log4j.appender.FLYS.File=/var/log/d4e-river/d4e-client.log -log4j.appender.FLYS.MaxFileSize=5000KB -log4j.appender.FLYS.MaxBackupIndex=3 +log4j.appender.FLYS=org.apache.log4j.ConsoleAppender +log4j.appender.FLYS.Target = System.out diff -r 0862ea5d66ba -r 28df64078f27 gwt-client/src/main/webapp/WEB-INF/web.xml --- a/gwt-client/src/main/webapp/WEB-INF/web.xml Thu Jan 18 20:54:03 2018 +0100 +++ b/gwt-client/src/main/webapp/WEB-INF/web.xml Fri Jan 19 11:23:42 2018 +0100 @@ -85,6 +85,8 @@ /flys/user + + server-info org.dive4elements.river.client.server.ServerInfoServiceImpl