gernotbelger@8854: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde gernotbelger@8854: * Software engineering by Intevation GmbH gernotbelger@8854: * gernotbelger@8854: * This file is Free Software under the GNU AGPL (>=v3) gernotbelger@8854: * and comes with ABSOLUTELY NO WARRANTY! Check out the gernotbelger@8854: * documentation coming with Dive4Elements River for details. gernotbelger@8854: */ gernotbelger@8854: gernotbelger@8854: package org.dive4elements.river.artifacts.sinfo.flowdepth; gernotbelger@8854: gernotbelger@8854: import java.io.OutputStream; gernotbelger@8854: import java.text.DateFormat; gernotbelger@8854: import java.text.NumberFormat; gernotbelger@8854: import java.util.ArrayList; gernotbelger@8854: import java.util.Collection; gernotbelger@8854: import java.util.Date; gernotbelger@8854: import java.util.HashMap; gernotbelger@8854: import java.util.Locale; gernotbelger@8854: import java.util.Map; gernotbelger@8854: gernotbelger@8854: import org.apache.log4j.Logger; gernotbelger@8854: import org.dive4elements.artifacts.CallMeta; gernotbelger@8854: import org.dive4elements.artifacts.common.utils.Config; gernotbelger@8854: import org.dive4elements.river.artifacts.model.CalculationResult; gernotbelger@8854: import org.dive4elements.river.artifacts.resources.Resources; gernotbelger@8854: import org.dive4elements.river.artifacts.sinfo.util.MetaAndTableJRDataSource; gernotbelger@8854: import org.dive4elements.river.exports.AbstractExporter; gernotbelger@8854: import org.dive4elements.river.model.River; gernotbelger@8854: import org.dive4elements.river.utils.Formatter; gernotbelger@8854: gernotbelger@8854: import au.com.bytecode.opencsv.CSVWriter; gernotbelger@8854: import net.sf.jasperreports.engine.JRDataSource; gernotbelger@8854: import net.sf.jasperreports.engine.JRException; gernotbelger@8854: import net.sf.jasperreports.engine.JasperExportManager; gernotbelger@8854: import net.sf.jasperreports.engine.JasperFillManager; gernotbelger@8854: import net.sf.jasperreports.engine.JasperPrint; gernotbelger@8854: gernotbelger@8854: /** gernotbelger@8854: * Generates different output formats (csv, pdf) of data that resulted from a flow depths computation. gernotbelger@8854: * gernotbelger@8854: * @author Ingo Weinzierl gernotbelger@8854: * @author Gernot Belger gernotbelger@8854: */ gernotbelger@8854: // REMARK: must be public because its registered in generators.xml gernotbelger@8854: public class FlowDepthExporter extends AbstractExporter { gernotbelger@8854: gernotbelger@8854: /** The log used in this exporter.*/ gernotbelger@8854: private static Logger log = Logger.getLogger(FlowDepthExporter.class); gernotbelger@8854: gernotbelger@8854: private static final String CSV_KM_HEADER = "sinfo.export.flow_depth.csv.header.km"; gernotbelger@8854: private static final String CSV_FLOWDEPTH_HEADER = "sinfo.export.flow_depth.csv.header.flowdepth"; gernotbelger@8854: private static final String CSV_FLOWDEPTHTKH_HEADER = "sinfo.export.flow_depth.csv.header.flowdepthTkh"; gernotbelger@8854: private static final String CSV_TKH_HEADER = "sinfo.export.flow_depth.csv.header.tkh"; gernotbelger@8854: private static final String CSV_WATERLEVEL_HEADER = "sinfo.export.flow_depth.csv.header.waterlevel"; gernotbelger@8854: private static final String CSV_DISCHARGE_HEADER = "sinfo.export.flow_depth.csv.header.discharge"; gernotbelger@8854: private static final String CSV_LABEL_HEADER = "sinfo.export.flow_depth.csv.header.label"; gernotbelger@8854: private static final String CSV_GAUGE_HEADER = "sinfo.export.flow_depth.csv.header.gauge"; gernotbelger@8854: private static final String CSV_MEAN_BED_HEIGHT_HEADER = "sinfo.export.flow_depth.csv.header.mean_bed_height"; gernotbelger@8854: private static final String CSV_SOUNDING_HEADER = "sinfo.export.flow_depth.csv.header.sounding"; gernotbelger@8854: private static final String CSV_LOCATION_HEADER = "sinfo.export.flow_depth.csv.header.location"; gernotbelger@8854: gernotbelger@8854: private static final String CSV_META_HEADER_RESULT = gernotbelger@8854: "sinfo.export.flow_depth.csv.meta.header.result"; gernotbelger@8854: gernotbelger@8854: private static final String CSV_META_VERSION = gernotbelger@8854: "sinfo.export.flow_depth.csv.meta.version"; gernotbelger@8854: gernotbelger@8854: private static final String CSV_META_USER = gernotbelger@8854: "sinfo.export.flow_depth.csv.meta.user"; gernotbelger@8854: gernotbelger@8854: private static final String CSV_META_CREATION = gernotbelger@8854: "sinfo.export.flow_depth.csv.meta.creation"; gernotbelger@8854: gernotbelger@8854: private static final String CSV_META_RIVER = gernotbelger@8854: "sinfo.export.flow_depth.csv.meta.river"; gernotbelger@8854: gernotbelger@8854: private static final String CSV_META_HEADER_SOUNDING = gernotbelger@8854: "sinfo.export.flow_depth.csv.meta.header.sounding"; gernotbelger@8854: gernotbelger@8854: private static final String CSV_META_HEADER_WATERLEVEL = gernotbelger@8854: "sinfo.export.flow_depth.csv.meta.header.waterlevel"; gernotbelger@8854: gernotbelger@8854: private static final String JASPER_FILE = "/jasper/sinfo.flowdepth.jasper"; //$NON-NLS-1$ gernotbelger@8854: gernotbelger@8854: /** The storage that contains the current calculation result.*/ gernotbelger@8854: private FlowDepthCalculationResults data = null; gernotbelger@8854: gernotbelger@8854: private NumberFormat meanBedHeightFormatter; gernotbelger@8854: gernotbelger@8854: private NumberFormat tkhFormatter; gernotbelger@8854: gernotbelger@8854: private NumberFormat flowDepthFormatter; gernotbelger@8854: gernotbelger@8854: private NumberFormat getMeanBedHeightFormatter() { gernotbelger@8854: if( meanBedHeightFormatter == null ) gernotbelger@8854: // FIXME: check if this is right gernotbelger@8854: meanBedHeightFormatter = Formatter.getMiddleBedHeightHeight(context); gernotbelger@8854: return meanBedHeightFormatter; gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: private NumberFormat getTkhFormatter() { gernotbelger@8854: if( tkhFormatter == null ) gernotbelger@8854: // FIXME: check if this is right, probably not, we need one digit gernotbelger@8854: tkhFormatter = Formatter.getWaterlevelW(context); gernotbelger@8854: return tkhFormatter; gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: private NumberFormat getFlowDepthFormatter() { gernotbelger@8854: if( flowDepthFormatter == null ) gernotbelger@8854: // FIXME: check if this is right gernotbelger@8854: flowDepthFormatter = Formatter.getMeterFormat(context); gernotbelger@8854: return flowDepthFormatter; gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: @Override gernotbelger@8854: protected void addData(Object d) { gernotbelger@8854: /* reset */ gernotbelger@8854: data = null; gernotbelger@8854: gernotbelger@8854: if (d instanceof CalculationResult) { gernotbelger@8854: gernotbelger@8854: final Object dat = ((CalculationResult)d).getData(); gernotbelger@8854: if( dat != null ) gernotbelger@8854: data = (FlowDepthCalculationResults)dat; gernotbelger@8854: } gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: @Override gernotbelger@8854: protected void writeCSVData(CSVWriter writer) { gernotbelger@8854: log.info("FlowDepthExporter.writeCSVData"); gernotbelger@8854: gernotbelger@8854: /* fetch calculation results */ gernotbelger@8854: final FlowDepthCalculationResults results = data; gernotbelger@8854: gernotbelger@8854: /* write as csv */ gernotbelger@8854: gernotbelger@8854: // boolean atGauge = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.WGAUGE; gernotbelger@8854: // boolean isQ = mode == WQ_MODE.QGAUGE || mode == WQ_MODE.QFREE; gernotbelger@8854: // RiverUtils.WQ_INPUT input gernotbelger@8854: // = RiverUtils.getWQInputMode((D4EArtifact)master); gernotbelger@8854: gernotbelger@8854: final boolean useTkh = results.isUseTkh(); gernotbelger@8854: gernotbelger@8854: writeCSVMeta(writer, results); gernotbelger@8854: writeCSVHeader(writer, useTkh); gernotbelger@8854: gernotbelger@8854: for (final FlowDepthCalculationResult result : results.getResults()) { gernotbelger@8854: writeCSVFlowDepthResult(writer, result, useTkh); gernotbelger@8854: } gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: private void writeCSVFlowDepthResult(final CSVWriter writer, final FlowDepthCalculationResult result, final boolean useTkh) { gernotbelger@8854: final Collection rows = result.getRows(); gernotbelger@8854: for (final FlowDepthRow flowDepthRow : rows) { gernotbelger@8854: writeCSVFlowDepthRow(writer, flowDepthRow, useTkh); gernotbelger@8854: } gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: private void writeCSVMeta(final CSVWriter writer, final FlowDepthCalculationResults results) { gernotbelger@8854: log.info("FlowDepthExporter.writeCSVMeta"); gernotbelger@8854: gernotbelger@8854: // Workflow zur Berechnung der Fließtiefe.pdf gernotbelger@8854: // "##ERGEBNISAUSGABE - Name des Gewässers - Fließtiefe" gernotbelger@8854: final River river = results.getRiver(); gernotbelger@8854: writeCSVMeataEntry(writer, CSV_META_HEADER_RESULT, river.getName() ); gernotbelger@8854: gernotbelger@8854: // "# FLYS-Version: " gernotbelger@8854: // FIXME gernotbelger@8854: final String flysVersion = "unbekannt"; gernotbelger@8854: writeCSVMeataEntry(writer, CSV_META_VERSION, flysVersion ); gernotbelger@8854: gernotbelger@8854: // "# Bearbeiter: " gernotbelger@8854: // FIXME gernotbelger@8854: final String user = "unbekannt"; gernotbelger@8854: writeCSVMeataEntry(writer, CSV_META_USER, user ); gernotbelger@8854: gernotbelger@8854: // "# Datum der Erstellung: " gernotbelger@8854: final Locale locale = Resources.getLocale(context.getMeta()); gernotbelger@8854: final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); gernotbelger@8854: writeCSVMeataEntry(writer, CSV_META_CREATION, df.format(new Date()) ); gernotbelger@8854: gernotbelger@8854: // "# Gewässer: " gernotbelger@8854: writeCSVMeataEntry(writer, CSV_META_RIVER, river.getName() ); gernotbelger@8854: gernotbelger@8854: // "# Höhensystem des Flusses: " gernotbelger@8854: gernotbelger@8854: // FIXME gernotbelger@8854: gernotbelger@8854: // "# Ort/Bereich (km): " gernotbelger@8854: // FIXME gernotbelger@8854: // TODO: unklar, es wird nur ein Bereich eingegeben gernotbelger@8854: // RangeAccess rangeAccess = new RangeAccess(flys); gernotbelger@8854: // double[] kms = rangeAccess.getKmRange(); gernotbelger@8854: // writer.writeNext(new String[] { gernotbelger@8854: // Resources.getMsg( gernotbelger@8854: // meta, gernotbelger@8854: // CSV_META_RANGE, gernotbelger@8854: // CSV_META_RANGE, gernotbelger@8854: // new Object[] { kms[0], kms[kms.length-1] }) gernotbelger@8854: // }); gernotbelger@8854: gernotbelger@8854: // "##METADATEN PEILUNG" gernotbelger@8854: writeCSVMeataEntry(writer, CSV_META_HEADER_SOUNDING ); gernotbelger@8854: gernotbelger@8854: // "# Jahr der Peilung: " gernotbelger@8854: // FIXME gernotbelger@8854: // "# Aufnahmeart: " gernotbelger@8854: // FIXME gernotbelger@8854: // "# Lagesystem: " gernotbelger@8854: // FIXME gernotbelger@8854: // "# Höhensystem: " gernotbelger@8854: // FIXME gernotbelger@8854: // "# ursprüngliches Höhensystem: " gernotbelger@8854: // FIXME gernotbelger@8854: // "##METADATEN WASSERSPIEGELLAGE" gernotbelger@8854: writeCSVMeataEntry(writer, CSV_META_HEADER_WATERLEVEL ); gernotbelger@8854: // "# Bezeichnung der Wasserspiegellage: " gernotbelger@8854: // FIXME gernotbelger@8854: // "# Höhensystem der Wasserspiegellage: " gernotbelger@8854: // FIXME gernotbelger@8854: // "# Auswerter: " gernotbelger@8854: // FIXME gernotbelger@8854: // "# Bezugspegel: " gernotbelger@8854: // FIXME gernotbelger@8854: // "# Jahr/Zeitraum der Wasserspiegellage: " gernotbelger@8854: // FIXME gernotbelger@8854: gernotbelger@8854: // "# W/Pegel [cm]: " (nur bei Eingabe des Wasserstands am Pegel) gernotbelger@8854: // TODO: unklar, es wird kein W eingegeben gernotbelger@8854: gernotbelger@8854: // "# Q (m³/s): " (nur bei Eingabe des Durchflusses) gernotbelger@8854: // TODO: unklar, es wird kein Q eingegeben gernotbelger@8854: gernotbelger@8854: // writer.writeNext(new String[] { gernotbelger@8854: // Resources.getMsg( gernotbelger@8854: // meta, gernotbelger@8854: // CSV_META_GAUGE, gernotbelger@8854: // CSV_META_GAUGE, gernotbelger@8854: // new Object[] { RiverUtils.getGaugename(flys) }) gernotbelger@8854: // }); gernotbelger@8854: gernotbelger@8854: writer.writeNext(new String[] { "" }); gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: gernotbelger@8854: private void writeCSVMeataEntry(CSVWriter writer, String message, Object... messageArgs) { gernotbelger@8854: gernotbelger@8854: CallMeta meta = context.getMeta(); gernotbelger@8854: gernotbelger@8854: writer.writeNext(new String[] { gernotbelger@8854: Resources.getMsg( gernotbelger@8854: meta, gernotbelger@8854: message, gernotbelger@8854: message, gernotbelger@8854: messageArgs) gernotbelger@8854: }); gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: /** gernotbelger@8854: * Write the header, with different headings depending on whether at a gernotbelger@8854: * gauge or at a location. gernotbelger@8854: * @param useTkh gernotbelger@8854: */ gernotbelger@8854: private void writeCSVHeader( gernotbelger@8854: final CSVWriter writer, gernotbelger@8854: final boolean useTkh gernotbelger@8854: ) { gernotbelger@8854: log.info("FlowDepthExporter.writeCSVHeader"); gernotbelger@8854: gernotbelger@8854: final Collection header = new ArrayList<>(11); gernotbelger@8854: gernotbelger@8854: header.add(msg(CSV_KM_HEADER,CSV_KM_HEADER)); gernotbelger@8854: header.add(msg(CSV_FLOWDEPTH_HEADER)); gernotbelger@8854: if( useTkh ) gernotbelger@8854: { gernotbelger@8854: header.add(msg(CSV_FLOWDEPTHTKH_HEADER)); gernotbelger@8854: header.add(msg(CSV_TKH_HEADER)); gernotbelger@8854: } gernotbelger@8854: header.add(msg(CSV_WATERLEVEL_HEADER)); gernotbelger@8854: header.add(msg(CSV_DISCHARGE_HEADER)); gernotbelger@8854: header.add(msg(CSV_LABEL_HEADER)); gernotbelger@8854: header.add(msg(CSV_GAUGE_HEADER)); gernotbelger@8854: header.add(msg(CSV_MEAN_BED_HEIGHT_HEADER)); gernotbelger@8854: header.add(msg(CSV_SOUNDING_HEADER)); gernotbelger@8854: header.add(msg(CSV_LOCATION_HEADER)); gernotbelger@8854: gernotbelger@8854: writer.writeNext(header.toArray(new String[header.size()])); gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: /** gernotbelger@8854: * Format a row of a flow depth result into an array of string, both used by csv and pdf gernotbelger@8854: * @param useTkh gernotbelger@8854: */ gernotbelger@8854: private String[] formatFlowDepthRow( gernotbelger@8854: final FlowDepthRow row, gernotbelger@8854: boolean useTkh ) { gernotbelger@8854: gernotbelger@8854: final Collection lines = new ArrayList<>(11); gernotbelger@8854: gernotbelger@8854: // Fluss-km gernotbelger@8854: lines.add( getKmFormatter().format( row.getStation() ) ); gernotbelger@8854: gernotbelger@8854: // Fließtiefe [m] gernotbelger@8854: lines.add( getFlowDepthFormatter().format( row.getFlowDepth() ) ); gernotbelger@8854: gernotbelger@8854: if( useTkh ) gernotbelger@8854: { gernotbelger@8854: // Fließtiefe mit TKH [m] gernotbelger@8854: lines.add( getFlowDepthFormatter().format( row.getFlowDepthWithTkh() ) ); gernotbelger@8854: gernotbelger@8854: // TKH [cm] gernotbelger@8854: lines.add( getTkhFormatter().format( row.getTkh() ) ); gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: // Wasserstand [NN + m] gernotbelger@8854: lines.add( getWFormatter().format( row.getWaterlevel() ) ); gernotbelger@8854: gernotbelger@8854: // Q [m³/s] gernotbelger@8854: lines.add( getQFormatter().format( row.getDischarge() ) ); gernotbelger@8854: gernotbelger@8854: // Bezeichnung gernotbelger@8854: lines.add( row.getWaterlevelLabel() ); gernotbelger@8854: gernotbelger@8854: // Bezugspegel gernotbelger@8854: lines.add( row.getGauge() ); gernotbelger@8854: gernotbelger@8854: // Mittlere Sohlhöhe [NN + m] gernotbelger@8854: lines.add( getMeanBedHeightFormatter().format( row.getMeanBedHeight( ) ) ); gernotbelger@8854: gernotbelger@8854: // Peilung/Epoche gernotbelger@8854: lines.add( row.getSoundageLabel() ); gernotbelger@8854: gernotbelger@8854: // Lage gernotbelger@8854: lines.add( row.getLocation() ); gernotbelger@8854: gernotbelger@8854: return lines.toArray(new String[lines.size()]); gernotbelger@8854: } gernotbelger@8854: /** gernotbelger@8854: * Write "rows" of csv data from wqkms with writer. gernotbelger@8854: * @param useTkh gernotbelger@8854: */ gernotbelger@8854: private void writeCSVFlowDepthRow( gernotbelger@8854: final CSVWriter writer, gernotbelger@8854: final FlowDepthRow row, gernotbelger@8854: final boolean useTkh gernotbelger@8854: ) { gernotbelger@8854: log.debug("FlowDepthExporter.writeCSVFlowDepthRow"); gernotbelger@8854: gernotbelger@8854: final String[] formattedRow = formatFlowDepthRow(row, useTkh); gernotbelger@8854: writer.writeNext( formattedRow ); gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: @Override gernotbelger@8854: protected void writePDF(OutputStream outStream) { gernotbelger@8854: log.debug("write PDF"); gernotbelger@8854: gernotbelger@8854: final JRDataSource source = createJRData(); gernotbelger@8854: gernotbelger@8854: final String confPath = Config.getConfigDirectory().toString(); gernotbelger@8854: gernotbelger@8854: // FIXME: distinguish between with and without tkh: we need two jasper reports! gernotbelger@8854: gernotbelger@8854: final Map parameters = new HashMap<>(); gernotbelger@8854: parameters.put("ReportTitle", "Exported Data"); gernotbelger@8854: try { gernotbelger@8854: final JasperPrint print = JasperFillManager.fillReport( gernotbelger@8854: confPath + JASPER_FILE, gernotbelger@8854: parameters, gernotbelger@8854: source); gernotbelger@8854: JasperExportManager.exportReportToPdfStream(print, outStream); gernotbelger@8854: } gernotbelger@8854: catch(JRException je) { gernotbelger@8854: log.warn("Error generating PDF Report!", je); gernotbelger@8854: } gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: private JRDataSource createJRData() { gernotbelger@8854: gernotbelger@8854: /* fetch calculation results */ gernotbelger@8854: final FlowDepthCalculationResults results = data; gernotbelger@8854: gernotbelger@8854: final MetaAndTableJRDataSource source = new MetaAndTableJRDataSource(); gernotbelger@8854: gernotbelger@8854: addJRMetaData(source, results); gernotbelger@8854: gernotbelger@8854: final boolean useTkh = results.isUseTkh(); gernotbelger@8854: gernotbelger@8854: for (final FlowDepthCalculationResult result : results.getResults()) { gernotbelger@8854: addJRTableData(source, result, useTkh); gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: return source; gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: private void addJRMetaData(final MetaAndTableJRDataSource source, FlowDepthCalculationResults results) { gernotbelger@8854: gernotbelger@8854: // Workflow zur Berechnung der Fließtiefe.pdf gernotbelger@8854: // "##ERGEBNISAUSGABE - Name des Gewässers - Fließtiefe" gernotbelger@8854: // writeCSVMeataEntry(writer, CSV_META_HEADER_RESULT, inputData.getRiver() ); gernotbelger@8854: gernotbelger@8854: // FIXME gernotbelger@8854: final String flysVersion = "unbekannt"; gernotbelger@8854: // CSV_META_VERSION gernotbelger@8854: source.addMetaData("version", flysVersion); gernotbelger@8854: gernotbelger@8854: // FIXME gernotbelger@8854: String user = "unbekannt"; gernotbelger@8854: // CSV_META_USER gernotbelger@8854: source.addMetaData("user", user); gernotbelger@8854: gernotbelger@8854: final Locale locale = Resources.getLocale(context.getMeta()); gernotbelger@8854: final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); gernotbelger@8854: source.addMetaData("date", df.format(new Date())); gernotbelger@8854: gernotbelger@8854: // CSV_META_RIVER gernotbelger@8854: source.addMetaData("river", results.getRiver().getName()); gernotbelger@8854: gernotbelger@8854: // FIXME gernotbelger@8854: source.addMetaData("range", "FIXME"); gernotbelger@8854: // "# Ort/Bereich (km): " gernotbelger@8854: // FIXME gernotbelger@8854: // TODO: unklar, es wird nur ein Bereich eingegeben gernotbelger@8854: // RangeAccess rangeAccess = new RangeAccess(flys); gernotbelger@8854: // double[] kms = rangeAccess.getKmRange(); gernotbelger@8854: // writer.writeNext(new String[] { gernotbelger@8854: // Resources.getMsg( gernotbelger@8854: // meta, gernotbelger@8854: // CSV_META_RANGE, gernotbelger@8854: // CSV_META_RANGE, gernotbelger@8854: // new Object[] { kms[0], kms[kms.length-1] }) gernotbelger@8854: // }); gernotbelger@8854: gernotbelger@8854: // RangeAccess rangeAccess = new RangeAccess(flys); gernotbelger@8854: // double[] kms = rangeAccess.getKmRange(); gernotbelger@8854: // source.addMetaData("range", gernotbelger@8854: // kmf.format(kms[0]) + " - " + kmf.format(kms[kms.length-1])); gernotbelger@8854: } gernotbelger@8854: gernotbelger@8854: private void addJRTableData(final MetaAndTableJRDataSource source, final FlowDepthCalculationResult result, final boolean useTkh) { gernotbelger@8854: gernotbelger@8854: final Collection rows = result.getRows(); gernotbelger@8854: gernotbelger@8854: for (final FlowDepthRow row : rows) { gernotbelger@8854: gernotbelger@8854: final String[] formattedRow = formatFlowDepthRow(row, useTkh); gernotbelger@8854: source.addData(formattedRow); gernotbelger@8854: } gernotbelger@8854: } gernotbelger@8854: }