Mercurial > dive4elements > river
changeset 9123:1cc7653ca84f
Cleanup of ChartGenerator and ChartGenerator2 code. Put some of the copy/pasted code into a common abstraction.
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoLineProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/AbstractSInfoLineProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -31,6 +31,8 @@ abstract class AbstractSInfoLineProcessor<RESULT extends AbstractSInfoCalculationResult> extends AbstractSInfoProcessor { + private static final double GAP_DISTANCE = 0.101; + public AbstractSInfoLineProcessor(final String i18nAxisLabel, final Set<String> handledFacetType) { super(i18nAxisLabel, handledFacetType); } @@ -38,7 +40,7 @@ @Override protected final String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { - final CallContext context = generator.getCallContext(); + final CallContext context = generator.getContext(); final Map<String, String> metaData = bundle.getFacet().getMetaData(); final Artifact artifact = bundle.getArtifact(); @@ -57,7 +59,7 @@ final double[][] points = generatePoints(context, artifact, data, facetName); - StyledSeriesBuilder.addPoints(series, points, true); + StyledSeriesBuilder.addPoints(series, points, true, GAP_DISTANCE); generator.addAxisSeries(series, getAxisName(), visible); return metaData.get("Y");
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthDevelopmentProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/FlowDepthDevelopmentProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -22,7 +22,7 @@ private static final String I18N_AXIS_LABEL = "sinfo.chart.flow_depth_development.section.yaxis.label"; - private static final String SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_YAXIS_LABEL = "sinfo.chart.flow_depth.yaxis.label"; + private static final String SINFO_CHART_FLOW_DEPTH_DEVELOPMENT_YAXIS_LABEL = "sinfo.chart.flow_depth_development.yaxis.label"; /* Theme name, usually defined in 'FacetTypes', but that is soooo bad dependencies... */ // REMARK: these must end with 'filtered' so extra handling happens in chart: point are always recalculated, because
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/InfrastructureHeightProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/InfrastructureHeightProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -56,7 +56,7 @@ @Override protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { - final CallContext context = generator.getCallContext(); + final CallContext context = generator.getContext(); final Map<String, String> metaData = bundle.getFacet().getMetaData(); final Artifact artifact = bundle.getArtifact();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelDepthProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelDepthProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -56,7 +56,7 @@ @Override protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { - final CallContext context = generator.getCallContext(); + final CallContext context = generator.getContext(); final Map<String, String> metaData = bundle.getFacet().getMetaData(); final Artifact artifact = bundle.getArtifact();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelWidthProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedChannelWidthProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -56,7 +56,7 @@ @Override protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { - final CallContext context = generator.getCallContext(); + final CallContext context = generator.getContext(); final Map<String, String> metaData = bundle.getFacet().getMetaData(); final Artifact artifact = bundle.getArtifact();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolPerYearProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolPerYearProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -56,7 +56,7 @@ @Override protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { - final CallContext context = generator.getCallContext(); + final CallContext context = generator.getContext(); final Map<String, String> metaData = bundle.getFacet().getMetaData(); final Artifact artifact = bundle.getArtifact();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedDepthEvolProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -56,7 +56,7 @@ @Override protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { - final CallContext context = generator.getCallContext(); + final CallContext context = generator.getContext(); final Map<String, String> metaData = bundle.getFacet().getMetaData(); final Artifact artifact = bundle.getArtifact();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedFlowDepthProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedFlowDepthProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -14,7 +14,6 @@ import java.util.Map; import java.util.Set; -import org.apache.log4j.Logger; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifacts.Artifact; import org.dive4elements.artifacts.CallContext; @@ -32,8 +31,6 @@ */ public class PredefinedFlowDepthProcessor extends AbstractSInfoProcessor { - private final static Logger log = Logger.getLogger(PredefinedFlowDepthProcessor.class); - public static final String FACET_PREDEFINED_FLOW_DEPTH = "sinfo_facet_predefined_flowdepth"; private static final String I18N_AXIS_LABEL = "sinfo.chart.flow_depth.section.yaxis.label"; @@ -51,7 +48,7 @@ @Override protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { - final CallContext context = generator.getCallContext(); + final CallContext context = generator.getContext(); final Map<String, String> metaData = bundle.getFacet().getMetaData(); final Artifact artifact = bundle.getArtifact();
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedTkhProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/PredefinedTkhProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -13,7 +13,6 @@ import java.util.HashSet; import java.util.Set; -import org.apache.log4j.Logger; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.exports.DiagramGenerator; @@ -30,8 +29,6 @@ */ public class PredefinedTkhProcessor extends AbstractSInfoProcessor { - private final static Logger log = Logger.getLogger(PredefinedTkhProcessor.class); - public static final String FACET_PREDEFINED_TKH = "sinfo_facet_predefined_tkh"; private static final String I18N_AXIS_LABEL = "sinfo.chart.tkh.section.yaxis.label"; @@ -48,7 +45,7 @@ @Override protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { - final CallContext context = generator.getCallContext(); + final CallContext context = generator.getContext(); final String facetName = bundle.getFacetName(); final AbstractTkhCalculationResult data = (AbstractTkhCalculationResult) bundle.getData(context);
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/sinfo/common/TkhProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -46,7 +46,7 @@ @Override protected String generateSeries(final DiagramGenerator generator, final ArtifactAndFacet bundle, final ThemeDocument theme, final boolean visible) { - final CallContext context = generator.getCallContext(); + final CallContext context = generator.getContext(); final String facetName = bundle.getFacetName(); final AbstractTkhCalculationResult data = (AbstractTkhCalculationResult) bundle.getData(context);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/AbstractChartGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/AbstractChartGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -9,52 +9,499 @@ */ package org.dive4elements.river.exports; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Paint; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.OutputStream; +import java.text.DateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + import javax.xml.xpath.XPathConstants; +import org.apache.log4j.Logger; +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifactdatabase.state.Settings; +import org.dive4elements.artifacts.Artifact; import org.dive4elements.artifacts.ArtifactNamespaceContext; import org.dive4elements.artifacts.CallContext; +import org.dive4elements.artifacts.CallMeta; +import org.dive4elements.artifacts.PreferredLocale; import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.river.FLYS; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.access.RangeAccess; import org.dive4elements.river.artifacts.access.RiverAccess; +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.artifacts.sinfo.util.CalculationUtils; +import org.dive4elements.river.collections.D4EArtifactCollection; +import org.dive4elements.river.jfree.AxisDataset; +import org.dive4elements.river.jfree.Bounds; +import org.dive4elements.river.jfree.DoubleBounds; +import org.dive4elements.river.jfree.EnhancedLineAndShapeRenderer; +import org.dive4elements.river.jfree.RiverAnnotation; +import org.dive4elements.river.jfree.StableXYDifferenceRenderer; +import org.dive4elements.river.jfree.Style; +import org.dive4elements.river.jfree.StyledAreaSeriesCollection; +import org.dive4elements.river.jfree.StyledSeries; +import org.dive4elements.river.themes.ThemeDocument; +import org.dive4elements.river.utils.Formatter; import org.jfree.chart.JFreeChart; +import org.jfree.chart.LegendItem; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.axis.NumberAxis; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.chart.title.TextTitle; +import org.jfree.data.Range; +import org.jfree.data.general.Series; +import org.jfree.data.xy.XYDataset; +import org.jfree.ui.RectangleInsets; import org.w3c.dom.Document; +import org.w3c.dom.Element; /** + * This class re-unites the tremendous copy/paste code from ChartGenerator and ChartGenerator2. Code is still awful and + * encapsulation is broken in too many places. + * TODO: instead of deep inheritances, delegate to classes that define the various behaviors. + * * @author Gernot Belger */ -// FIXME: this class is intended to contain all duplicate code from ChartGenerator and ChartGenerator2; who will clean -// up this mess...? abstract class AbstractChartGenerator implements OutGenerator { + + protected static final Logger log = Logger.getLogger(AbstractChartGenerator.class); + + private static final int DEFAULT_CHART_WIDTH = 600; + + private static final int DEFAULT_CHART_HEIGHT = 400; + + private static final Color DEFAULT_GRID_COLOR = Color.GRAY; + + private static final float DEFAULT_GRID_LINE_WIDTH = 0.3f; + + protected static final String DEFAULT_FONT_NAME = "Tahoma"; + + protected static final int DEFAULT_FONT_SIZE = 12; + + private static final String DEFAULT_CHART_FORMAT = "png"; + private static final String XPATH_CHART_EXPORT = "/art:action/art:attributes/art:export/@art:value"; - // TODO: move real code here - protected abstract D4EArtifact getArtifact(); + private static final String XPATH_CHART_SIZE = "/art:action/art:attributes/art:size"; + + private static final String XPATH_CHART_FORMAT = "/art:action/art:attributes/art:format/@art:value"; + + private static final String XPATH_CHART_X_RANGE = "/art:action/art:attributes/art:xrange"; + + private static final String XPATH_CHART_Y_RANGE = "/art:action/art:attributes/art:yrange"; + + /** The document of the incoming out() request. */ + private Document request; + + /** The output stream where the data should be written to. */ + private OutputStream out; + + /** Artifact that is used to decorate the chart with meta information. */ + private Artifact master; + + /** Map of datasets ("index"). */ + private final SortedMap<Integer, AxisDataset> datasets = new TreeMap<>(); + + /** List of annotations to insert in plot. */ + private final List<RiverAnnotation> annotations = new ArrayList<>(); + + private String outName; + + /** The settings that should be used during output creation. */ + private Settings settings; /** The CallContext object. */ - // TODO: move real code here - protected abstract CallContext getContext(); + private CallContext context; + + @Override + public void init(final String outName, final Document request, final OutputStream out, final CallContext context) { + log.debug("ChartGenerator.init"); + + this.outName = outName; + this.request = request; + this.out = out; + this.context = context; + } + + @Override + public void setup(final Object config) { + } + + /** Sets the master artifact. */ + @Override + public void setMasterArtifact(final Artifact master) { + this.master = master; + } + + /** + * Gets the master artifact. + * + * @return the master artifact. + */ + public Artifact getMaster() { + return this.master; + } + + protected final Map<Integer, AxisDataset> getDatasets() { + return this.datasets; + } + + @Override + public void setCollection(final D4EArtifactCollection collection) { + /* we do not need it */ + } + + protected final D4EArtifact getArtifact() { + // FIXME: should already made sure when this member is set + return (D4EArtifact) this.master; + } + + public final CallContext getContext() { + return this.context; + } /** The document of the incoming out() request. */ - // TODO: move real code here - protected abstract Document getRequest(); + protected final Document getRequest() { + return this.request; + } + + /** + * Adds annotations to list. The given annotation will be visible. + */ + public final void addAnnotations(final RiverAnnotation annotation) { + this.annotations.add(annotation); + } + + /** + * This method needs to be implemented by concrete subclasses to create new + * instances of JFreeChart. + * + * @param context2 + * + * @return a new instance of a JFreeChart. + */ + protected abstract JFreeChart generateChart(CallContext context2); + + /** + * For every outable (i.e. facets), this function is + * called and handles the data accordingly. + */ + @Override + public abstract void doOut(ArtifactAndFacet bundle, ThemeDocument attr, boolean visible); + + @Override + public void generate() throws IOException { + doGenerate(this.context, this.out, this.outName); + } + + protected abstract void doGenerate(CallContext context, OutputStream out, String outName) throws IOException; + + protected abstract Series getSeriesOf(XYDataset dataset, int idx); + + /** + * Returns the default title of a chart. + * + * @param context2 + * + * @return the default title of a chart. + */ + protected abstract String getDefaultChartTitle(CallContext context); + + /** + * This method is used to create new AxisDataset instances which may differ + * in concrete subclasses. + * + * @param idx + * The index of an axis. + */ + protected abstract AxisDataset createAxisDataset(int idx); + + /** + * Combines the ranges of the X axis at index <i>idx</i>. + * + * @param bounds + * A new Bounds. + * @param idx + * The index of the X axis that should be comined with + * <i>range</i>. + */ + protected abstract void combineXBounds(Bounds bounds, int idx); + + /** + * Combines the ranges of the Y axis at index <i>idx</i>. + * + * @param bounds + * A new Bounds. + * @param index + * The index of the Y axis that should be comined with. + * <i>range</i>. + */ + protected abstract void combineYBounds(Bounds bounds, int index); + + /** + * This method is used to determine the ranges for axes at a given index. + * + * @param index + * The index of the axes at the plot. + * + * @return a Range[] with [xrange, yrange]; + */ + protected abstract Range[] getRangesForAxis(int index); + + protected abstract Bounds getXBounds(int axis); + + protected abstract void setXBounds(int axis, Bounds bounds); + + protected abstract Bounds getYBounds(int axis); + + protected abstract void setYBounds(int axis, Bounds bounds); + + // /** + // * Retuns the call context. May be null if init hasn't been called yet. + // * + // * @return the CallContext instance + // */ + // protected final CallContext getCallContext() { + // return this.context; + // } + // + + @Override + public final void setSettings(final Settings settings) { + this.settings = settings; + } + + /** + * Returns the <i>settings</i> as <i>ChartSettings</i>. + * + * @return the <i>settings</i> as <i>ChartSettings</i> or null, if + * <i>settings</i> is not an instance of <i>ChartSettings</i>. + */ + protected final ChartSettings getChartSettings() { + if (this.settings instanceof ChartSettings) { + return (ChartSettings) this.settings; + } + + return null; + } + + /** + * Return instance of <i>ChartSettings</i> with a chart specific section + * but with no axes settings. + * + * @return an instance of <i>ChartSettings</i>. + */ + @Override + public final Settings getSettings() { + if (this.settings != null) + return this.settings; + + final ChartSettings settings = new ChartSettings(); + + final ChartSection chartSection = buildChartSection(this.context); + final LegendSection legendSection = buildLegendSection(); + final ExportSection exportSection = buildExportSection(); + + settings.setChartSection(chartSection); + settings.setLegendSection(legendSection); + settings.setExportSection(exportSection); + + final List<AxisSection> axisSections = buildAxisSections(); + for (final AxisSection axisSection : axisSections) + settings.addAxisSection(axisSection); + + return settings; + } + + protected abstract ChartSection buildChartSection(CallContext context); + + /** + * Creates a new <i>LegendSection</i>. + * + * @return a new <i>LegendSection</i>. + */ + private LegendSection buildLegendSection() { + final LegendSection legendSection = new LegendSection(); + legendSection.setVisibility(isLegendVisible()); + legendSection.setFontSize(getLegendFontSize()); + legendSection.setAggregationThreshold(10); + return legendSection; + } + + /** + * Creates a new <i>ExportSection</i> with default values <b>WIDTH=600</b> + * and <b>HEIGHT=400</b>. + * + * @return a new <i>ExportSection</i>. + */ + private ExportSection buildExportSection() { + final ExportSection exportSection = new ExportSection(); + exportSection.setWidth(DEFAULT_CHART_WIDTH); + exportSection.setHeight(DEFAULT_CHART_HEIGHT); + exportSection.setMetadata(true); + return exportSection; + } + + /** + * Creates a list of Sections that contains all axes of the chart (including + * X and Y axes). + * + * @return a list of Sections for each axis in this chart. + */ + private List<AxisSection> buildAxisSections() { + final List<AxisSection> axisSections = new ArrayList<>(); + + axisSections.addAll(buildXAxisSections()); + axisSections.addAll(buildYAxisSections()); + + return axisSections; + } + + /** + * Creates a new Section for chart's X axis. + * + * @return a List that contains a Section for the X axis. + */ + protected List<AxisSection> buildXAxisSections() { + final List<AxisSection> axisSections = new ArrayList<>(); + + final String identifier = "X"; + + final AxisSection axisSection = new AxisSection(); + axisSection.setIdentifier(identifier); + axisSection.setLabel(getXAxisLabel()); + axisSection.setFontSize(14); + axisSection.setFixed(false); + + // XXX We are able to find better default ranges that [0,0], but the Y + // axes currently have no better ranges set. + axisSection.setUpperRange(0d); + axisSection.setLowerRange(0d); + + axisSections.add(axisSection); + + return axisSections; + } + + /** + * Returns the X-Axis label of a chart. + * + * @return the X-Axis label of a chart. + */ + protected final String getXAxisLabel() { + final ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return getDefaultXAxisLabel(this.context); + } + + final AxisSection as = chartSettings.getAxisSection("X"); + if (as != null) { + final String label = as.getLabel(); + + if (label != null) { + return label; + } + } + + return getDefaultXAxisLabel(this.context); + } + + protected abstract List<AxisSection> buildYAxisSections(); + + /** + * Returns the default X-Axis label of a chart. + * + * @param context2 + * + * @return the default X-Axis label of a chart. + */ + protected abstract String getDefaultXAxisLabel(final CallContext context2); + + /** Generate the diagram as an image. */ + protected final void generateImage(final CallContext context) throws IOException { + log.debug("ChartGenerator2.generateImage"); + + final JFreeChart chart = generateChart(context); + + final String format = getFormat(); + int[] size = getSize(); + + if (size == null) + size = getExportDimension(); + + this.context.putContextValue("chart.width", size[0]); + this.context.putContextValue("chart.height", size[1]); + + if (format.equals(ChartExportHelper.FORMAT_PNG)) { + this.context.putContextValue("chart.image.format", "png"); + + ChartExportHelper.exportImage(this.out, chart, this.context); + } else if (format.equals(ChartExportHelper.FORMAT_PDF)) { + preparePDFContext(this.context); + + ChartExportHelper.exportPDF(this.out, chart, this.context); + } else if (format.equals(ChartExportHelper.FORMAT_SVG)) { + prepareSVGContext(this.context); + + ChartExportHelper.exportSVG(this.out, chart, this.context); + } else if (format.equals(ChartExportHelper.FORMAT_CSV)) { + this.context.putContextValue("chart.image.format", "csv"); + + ChartExportHelper.exportCSV(this.out, chart, this.context); + } + } /** * Adds a metadata sub-title to the chart if it gets exported */ - protected final void addMetadataSubtitle(final JFreeChart chart) { - if (isExport()) { - final String text = ChartExportHelper.createMetadataSubtitle(getArtifact(), getContext(), getRiverName()); - chart.addSubtitle(new TextTitle(text)); - } + protected final void addMetadataSubtitle(final CallContext context, final JFreeChart chart) { + if ((!isExport() || !isExportMetadata())) + return; + + final String version = FLYS.VERSION; + final String user = CalculationUtils.findArtifactUser(context, getArtifact()); + final Locale locale = Resources.getLocale(context.getMeta()); + final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); + final String dateText = df.format(new Date()); + + final String text = Resources.getMsg(context.getMeta(), "chart.subtitle.metadata", "default", version, user, dateText); + + chart.addSubtitle(new TextTitle(text)); + } + + private boolean isExportMetadata() { + final ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) + return true; + + final ExportSection exportSection = chartSettings.getExportSection(); + if (exportSection == null) + return true; + + return exportSection.getMetadata(); } /** * This method returns the export flag specified in the <i>request</i> document * or <i>false</i> if no export is specified in <i>request</i>. */ - protected final boolean isExport() { + private boolean isExport() { final Boolean export = (Boolean) XMLUtils.xpath(getRequest(), XPATH_CHART_EXPORT, XPathConstants.BOOLEAN, ArtifactNamespaceContext.INSTANCE); return export == null ? false : export; @@ -74,4 +521,790 @@ final RangeAccess rangeAccess = new RangeAccess(flys); return rangeAccess.getKmRange(); } + + /** + * Returns a boolean object that determines if the chart grid should be + * visible or not. This information needs to be provided by <i>settings</i>, + * otherwise the default is true. + * + * @param settings + * A ChartSettings object. + * + * @return true, if the chart grid should be visible otherwise false. + * + * @throws NullPointerException + * if <i>settings</i> is null. + */ + private boolean isGridVisible(final ChartSettings settings) { + final ChartSection cs = settings.getChartSection(); + return cs.getDisplayGrid(); + } + + /** + * This method is used to determine, if the chart's legend is visible or + * not. If a <i>settings</i> instance is set, this instance determines the + * visibility otherwise, this method returns true as default if no + * <i>settings</i> is set. + * + * @return true, if the legend should be visible, otherwise false. + */ + protected final boolean isLegendVisible() { + final ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) + return true; + + final LegendSection ls = chartSettings.getLegendSection(); + return ls.getVisibility(); + } + + /** + * This method returns the font size for the X axis. If the font size is + * specified in ChartSettings (if <i>chartSettings</i> is set), this size is + * returned. Otherwise the default font size 12 is returned. + * + * @return the font size for the x axis. + */ + protected final int getXAxisLabelFontSize() { + final ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) { + return DEFAULT_FONT_SIZE; + } + + final AxisSection as = chartSettings.getAxisSection("X"); + final Integer fontSize = as.getFontSize(); + + return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; + } + + /** + * This method is used to determine the font size of the chart's legend. If + * a <i>settings</i> instance is set, this instance determines the font + * size, otherwise this method returns 12 as default if no <i>settings</i> + * is set or if it doesn't provide a legend font size. + * + * @return a legend font size. + */ + private int getLegendFontSize() { + + final ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) + return DEFAULT_FONT_SIZE; + + final LegendSection ls = chartSettings.getLegendSection(); + if (ls == null) + return DEFAULT_FONT_SIZE; + + final Integer fontSize = ls.getFontSize(); + if (fontSize == null) + return DEFAULT_FONT_SIZE; + + return fontSize; + } + + /** + * Creates a new LegendItem with <i>name</i> and font provided by + * <i>createLegendLabelFont()</i>. + * + * @param theme + * The theme of the chart line. + * @param name + * The displayed name of the item. + * + * @return a new LegendItem instance. + */ + protected final LegendItem createLegendItem(final ThemeDocument theme, final String name) { + // OPTIMIZE Pass font, parsed Theme items. + + Color color = theme.parseLineColorField(); + if (color == null) + color = Color.BLACK; + + final LegendItem legendItem = new LegendItem(name, color); + legendItem.setLabelFont(createLegendLabelFont()); + return legendItem; + } + + /** + * Create new legend entries, dependent on settings. + * + * @param plot + * The plot for which to modify the legend. + */ + protected final void aggregateLegendEntries(final XYPlot plot) { + + final ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) + return; + + final Integer threshold = chartSettings.getLegendSection().getAggregationThreshold(); + + final int aggrThreshold = threshold != null ? threshold.intValue() : 0; + + LegendProcessor.aggregateLegendEntries(plot, aggrThreshold); + } + + /** + * Creates Font (Family and size) to use when creating Legend Items. The + * font size depends in the return value of <i>getLegendFontSize()</i>. + * + * @return a new Font instance with <i>DEFAULT_FONT_NAME</i>. + */ + private final Font createLegendLabelFont() { + return new Font(DEFAULT_FONT_NAME, Font.PLAIN, getLegendFontSize()); + } + + /** + * Adjust some Stroke/Grid parameters for <i>plot</i>. The chart + * <i>Settings</i> are applied in this method. + * + * @param plot + * The XYPlot which is adapted. + */ + protected void adjustPlot(final XYPlot plot) { + final Stroke gridStroke = new BasicStroke(DEFAULT_GRID_LINE_WIDTH, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 3.0f, new float[] { 3.0f }, 0.0f); + + final ChartSettings cs = getChartSettings(); + final boolean isGridVisible = cs != null ? isGridVisible(cs) : true; + + plot.setDomainGridlineStroke(gridStroke); + plot.setDomainGridlinePaint(DEFAULT_GRID_COLOR); + plot.setDomainGridlinesVisible(isGridVisible); + + plot.setRangeGridlineStroke(gridStroke); + plot.setRangeGridlinePaint(DEFAULT_GRID_COLOR); + plot.setRangeGridlinesVisible(isGridVisible); + + plot.setAxisOffset(new RectangleInsets(0d, 0d, 0d, 0d)); + } + + /** + * This helper method is used to extract the current locale from instance variable <i>context</i>. + * + * @return the current locale. + */ + protected final Locale getLocale() { + final CallMeta meta = this.context.getMeta(); + final PreferredLocale[] prefs = meta.getLanguages(); + + final int len = prefs != null ? prefs.length : 0; + + final Locale[] locales = new Locale[len]; + + for (int i = 0; i < len; i++) { + locales[i] = prefs[i].getLocale(); + } + + return meta.getPreferredLocale(locales); + } + + /** + * Look up \param key in i18n dictionary. + * + * @param key + * key for which to find i18nd version. + * @param def + * default, returned if lookup failed. + * @return value found in i18n dictionary, \param def if no value found. + */ + public final String msg(final String key, final String def) { + return Resources.getMsg(this.context.getMeta(), key, def); + } + + /** + * Look up \param key in i18n dictionary. + * + * @param key + * key for which to find i18nd version. + * @return value found in i18n dictionary, key itself if failed. + */ + public final String msg(final String key) { + return Resources.getMsg(this.context.getMeta(), key, key); + } + + public final String msg(final String key, final String def, final Object[] args) { + return Resources.getMsg(this.context.getMeta(), key, def, args); + } + + /** + * Add datasets stored in instance variable <i>datasets</i> to plot. + * <i>datasets</i> actually stores instances of AxisDataset, so each of this + * datasets is mapped to a specific axis as well. + * + * @param plot + * plot to add datasets to. + */ + protected void addDatasets(final XYPlot plot) { + log.debug("addDatasets()"); + + // AxisDatasets are sorted, but some might be empty. + // Thus, generate numbering on the fly. + int axisIndex = 0; + int datasetIndex = 0; + + for (final Map.Entry<Integer, AxisDataset> entry : this.datasets.entrySet()) { + if (!entry.getValue().isEmpty()) { + // Add axis and range information. + final AxisDataset axisDataset = entry.getValue(); + final NumberAxis axis = createYAxis(entry.getKey()); + + plot.setRangeAxis(axisIndex, axis); + + if (axis.getAutoRangeIncludesZero()) { + axisDataset.setRange(Range.expandToInclude(axisDataset.getRange(), 0d)); + } + + setYBounds(axisIndex, expandPointRange(axisDataset.getRange())); + + // Add contained datasets, mapping to axis. + for (final XYDataset dataset : axisDataset.getDatasets()) { + try { + plot.setDataset(datasetIndex, dataset); + plot.mapDatasetToRangeAxis(datasetIndex, axisIndex); + + applyThemes(plot, dataset, datasetIndex, axisDataset.isArea(dataset)); + + datasetIndex++; + } + catch (final RuntimeException re) { + log.error(re); + } + } + + axisDataset.setPlotAxisIndex(axisIndex); + axisIndex++; + } + } + } + + /** + * Create Y (range) axis for given index. + * Shall be implemented by subclasses. + */ + protected abstract NumberAxis createYAxis(final int index); + + /** + * @param idx + * "index" of dataset/series (first dataset to be drawn has + * index 0), correlates with renderer index. + * @param isArea + * true if the series describes an area and shall be rendered + * as such. + */ + private void applyThemes(final XYPlot plot, final XYDataset series, final int idx, final boolean isArea) { + if (isArea) { + applyAreaTheme(plot, (StyledAreaSeriesCollection) series, idx); + } else { + applyLineTheme(plot, series, idx); + } + } + + /** + * Expands a given range if it collapses into one point. + * + * @param range + * Range to be expanded if upper == lower bound. + * + * @return Bounds of point plus 5 percent in each direction. + */ + private Bounds expandPointRange(final Range range) { + if (range == null) { + return null; + } else if (range.getLowerBound() == range.getUpperBound()) { + final Range expandedRange = ChartHelper.expandRange(range, 5d); + return new DoubleBounds(expandedRange.getLowerBound(), expandedRange.getUpperBound()); + } + + return new DoubleBounds(range.getLowerBound(), range.getUpperBound()); + } + + /** + * Creates a new instance of EnhancedLineAndShapeRenderer. + * + * @param plot + * The plot which is set for the new renderer. + * @param idx + * This value is not used in the current implementation. + * + * @return a new instance of EnhancedLineAndShapeRenderer. + */ + private XYLineAndShapeRenderer createRenderer(final XYPlot plot, final int idx) { + log.debug("Create EnhancedLineAndShapeRenderer for idx: " + idx); + + final EnhancedLineAndShapeRenderer r = new EnhancedLineAndShapeRenderer(true, false); + + r.setPlot(plot); + + return r; + } + + /** + * This method applies the themes defined in the series itself. Therefore, + * <i>StyledXYSeries.applyTheme()</i> is called, which modifies the renderer + * for the series. + * + * @param plot + * The plot. + * @param dataset + * The XYDataset which needs to support Series objects. + * @param idx + * The index of the renderer / dataset. + */ + private void applyLineTheme(final XYPlot plot, final XYDataset dataset, final int idx) { + log.debug("Apply LineTheme for dataset at index: " + idx); + + final LegendItemCollection lic = new LegendItemCollection(); + final LegendItemCollection anno = plot.getFixedLegendItems(); + + final Font legendFont = createLegendLabelFont(); + + final XYLineAndShapeRenderer renderer = createRenderer(plot, idx); + + for (int s = 0, num = dataset.getSeriesCount(); s < num; s++) { + final Series series = getSeriesOf(dataset, s); + + if (series instanceof StyledSeries) { + final Style style = ((StyledSeries) series).getStyle(); + style.applyTheme(renderer, s); + } + + // special case: if there is just one single item, we need to enable + // points for this series, otherwise we would not see anything in + // the chart area. + if (series.getItemCount() == 1) { + renderer.setSeriesShapesVisible(s, true); + } + + LegendItem legendItem = renderer.getLegendItem(idx, s); + if (legendItem.getLabel().endsWith(" ") || legendItem.getLabel().endsWith("interpol")) { + legendItem = null; + } + + if (legendItem != null) { + legendItem.setLabelFont(legendFont); + lic.add(legendItem); + } else { + log.warn("Could not get LegentItem for renderer: " + idx + ", series-idx " + s); + } + } + + if (anno != null) { + lic.addAll(anno); + } + + plot.setFixedLegendItems(lic); + + plot.setRenderer(idx, renderer); + } + + /** + * @param plot + * The plot. + * @param area + * A StyledAreaSeriesCollection object. + * @param idx + * The index of the dataset. + */ + private final void applyAreaTheme(final XYPlot plot, final StyledAreaSeriesCollection area, final int idx) { + final LegendItemCollection lic = new LegendItemCollection(); + final LegendItemCollection anno = plot.getFixedLegendItems(); + + final Font legendFont = createLegendLabelFont(); + + log.debug("Registering an 'area'renderer at idx: " + idx); + + final StableXYDifferenceRenderer dRenderer = new StableXYDifferenceRenderer(); + + if (area.getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) { + dRenderer.setPositivePaint(createTransparentPaint()); + } + + plot.setRenderer(idx, dRenderer); + + area.applyTheme(dRenderer); + + // i18n + dRenderer.setAreaLabelNumberFormat(Formatter.getFormatter(this.context.getMeta(), 2, 4)); + + dRenderer.setAreaLabelTemplate(Resources.getMsg(this.context.getMeta(), "area.label.template", "Area=%sm2")); + + final LegendItem legendItem = dRenderer.getLegendItem(idx, 0); + if (legendItem != null) { + legendItem.setLabelFont(legendFont); + lic.add(legendItem); + } else { + log.warn("Could not get LegentItem for renderer: " + idx + ", series-idx " + 0); + } + + if (anno != null) { + lic.addAll(anno); + } + + plot.setFixedLegendItems(lic); + } + + /** + * Returns a transparently textured paint. + * + * @return a transparently textured paint. + */ + private static Paint createTransparentPaint() { + // TODO why not use a transparent color? + final BufferedImage texture = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR); + + return new TexturePaint(texture, new Rectangle2D.Double(0d, 0d, 0d, 0d)); + } + + private void preparePDFContext(final CallContext context) { + final int[] dimension = getExportDimension(); + + context.putContextValue("chart.width", dimension[0]); + context.putContextValue("chart.height", dimension[1]); + context.putContextValue("chart.marginLeft", 5f); + context.putContextValue("chart.marginRight", 5f); + context.putContextValue("chart.marginTop", 5f); + context.putContextValue("chart.marginBottom", 5f); + context.putContextValue("chart.page.format", ChartExportHelper.DEFAULT_PAGE_SIZE); + } + + private void prepareSVGContext(final CallContext context) { + final int[] dimension = getExportDimension(); + + context.putContextValue("chart.width", dimension[0]); + context.putContextValue("chart.height", dimension[1]); + context.putContextValue("chart.encoding", ChartExportHelper.DEFAULT_ENCODING); + } + + /** + * This method retrieves the chart subtitle by calling getChartSubtitle() + * and adds it as TextTitle to the chart. + * The default implementation of getChartSubtitle() returns the same + * as getDefaultChartSubtitle() which must be implemented by derived + * classes. If you want to add multiple subtitles to the chart override + * this method and add your subtitles manually. + * + * @param chart + * The JFreeChart chart object. + */ + protected void addSubtitles(final CallContext context, final JFreeChart chart) { + final String subtitle = getChartSubtitle(this.context); + + if (subtitle != null && subtitle.length() > 0) { + chart.addSubtitle(new TextTitle(subtitle)); + } + } + + protected abstract String getChartSubtitle(CallContext context); + + /** + * Adds a new AxisDataset which contains <i>dataset</i> at index <i>idx</i>. + * + * @param dataset + * An XYDataset. + * @param idx + * The axis index. + * @param visible + * Determines, if the dataset should be visible or not. + */ + protected final void addAxisDataset(final XYDataset dataset, final int idx, final boolean visible) { + if (dataset == null || idx < 0) { + return; + } + + final AxisDataset axisDataset = getAxisDataset(idx); + + final Bounds[] xyBounds = ChartHelper.getBounds(dataset); + + if (xyBounds == null) { + log.warn("Skip XYDataset for Axis (invalid ranges): " + idx); + return; + } + + if (visible) { + if (log.isDebugEnabled()) { + log.debug("Add new AxisDataset at index: " + idx); + log.debug("X extent: " + xyBounds[0]); + log.debug("Y extent: " + xyBounds[1]); + } + + axisDataset.addDataset(dataset); + } + + combineXBounds(xyBounds[0], 0); + combineYBounds(xyBounds[1], idx); + } + + /** + * This method grants access to the AxisDatasets stored in <i>datasets</i>. + * If no AxisDataset exists for index <i>idx</i>, a new AxisDataset is + * created using <i>createAxisDataset()</i>. + * + * @param idx + * The index of the desired AxisDataset. + * + * @return an existing or new AxisDataset. + */ + protected final AxisDataset getAxisDataset(final int idx) { + AxisDataset axisDataset = this.datasets.get(idx); + + if (axisDataset == null) { + axisDataset = createAxisDataset(idx); + this.datasets.put(idx, axisDataset); + } + + return axisDataset; + } + + /** + * Returns the size of a chart export as array which has been specified by + * the incoming request document. + * + * @return the size of a chart as [width, height] or null if no width or + * height are given in the request document. + */ + protected final int[] getSize() { + final int[] size = new int[2]; + + final Element sizeEl = (Element) XMLUtils.xpath(this.request, XPATH_CHART_SIZE, XPathConstants.NODE, ArtifactNamespaceContext.INSTANCE); + + if (sizeEl != null) { + final String uri = ArtifactNamespaceContext.NAMESPACE_URI; + + final String w = sizeEl.getAttributeNS(uri, "width"); + final String h = sizeEl.getAttributeNS(uri, "height"); + + if (w.length() > 0 && h.length() > 0) { + try { + size[0] = Integer.parseInt(w); + size[1] = Integer.parseInt(h); + } + catch (final NumberFormatException nfe) { + log.warn("Wrong values for chart width/height."); + } + } + } + + return size[0] > 0 && size[1] > 0 ? size : null; + } + + /** + * This method returns the format specified in the <i>request</i> document + * or <i>DEFAULT_CHART_FORMAT</i> if no format is specified in + * <i>request</i>. + * + * @return the format used to export this chart. + */ + private String getFormat() { + final String format = (String) XMLUtils.xpath(this.request, XPATH_CHART_FORMAT, XPathConstants.STRING, ArtifactNamespaceContext.INSTANCE); + + return format == null || format.length() == 0 ? DEFAULT_CHART_FORMAT : format; + } + + /** + * Returns the X-Axis range as String array from request document. + * If the (x|y)range elements are not found in request document, return + * null (i.e. not zoomed). + * + * @return a String array with [lower, upper], null if not in document. + */ + protected final String[] getDomainAxisRangeFromRequest() { + final Element xrange = (Element) XMLUtils.xpath(this.request, XPATH_CHART_X_RANGE, XPathConstants.NODE, ArtifactNamespaceContext.INSTANCE); + + if (xrange == null) { + return null; + } + + final String uri = ArtifactNamespaceContext.NAMESPACE_URI; + + final String lower = xrange.getAttributeNS(uri, "from"); + final String upper = xrange.getAttributeNS(uri, "to"); + + return new String[] { lower, upper }; + } + + /** + * Returns null if the (x|y)range-element was not found in + * request document. + * This usally means that the axis are not manually zoomed, i.e. showing + * full data extent. + */ + protected final String[] getValueAxisRangeFromRequest() { + final Element yrange = (Element) XMLUtils.xpath(this.request, XPATH_CHART_Y_RANGE, XPathConstants.NODE, ArtifactNamespaceContext.INSTANCE); + + if (yrange == null) { + return null; + } + + final String uri = ArtifactNamespaceContext.NAMESPACE_URI; + + final String lower = yrange.getAttributeNS(uri, "from"); + final String upper = yrange.getAttributeNS(uri, "to"); + + return new String[] { lower, upper }; + } + + /** + * Returns the default size of a chart export as array. + * + * @return the default size of a chart as [width, height]. + */ + protected final int[] getDefaultSize() { + return new int[] { DEFAULT_CHART_WIDTH, DEFAULT_CHART_HEIGHT }; + } + + /** + * This method returns the export dimension specified in ChartSettings as + * int array [width,height]. + * + * @return an int array with [width,height]. + */ + private int[] getExportDimension() { + final ChartSettings chartSettings = getChartSettings(); + if (chartSettings == null) + return new int[] { DEFAULT_CHART_WIDTH, DEFAULT_CHART_HEIGHT }; + + final ExportSection export = chartSettings.getExportSection(); + final Integer width = export.getWidth(); + final Integer height = export.getHeight(); + + if (width != null && height != null) { + return new int[] { width, height }; + } + + return new int[] { 600, 400 }; + } + + /** + * Returns the chart title provided by <i>settings</i>. + * + * @param settings + * A ChartSettings object. + * + * @return the title provided by <i>settings</i> or null if no + * <i>ChartSection</i> is provided by <i>settings</i>. + * + * @throws NullPointerException + * if <i>settings</i> is null. + */ + private String getChartTitle(final ChartSettings settings) { + final ChartSection cs = settings.getChartSection(); + return cs != null ? cs.getTitle() : null; + } + + /** + * Returns the chart subtitle provided by <i>settings</i>. + * + * @param settings + * A ChartSettings object. + * + * @return the subtitle provided by <i>settings</i> or null if no + * <i>ChartSection</i> is provided by <i>settings</i>. + * + * @throws NullPointerException + * if <i>settings</i> is null. + */ + protected final String getChartSubtitle(final ChartSettings settings) { + final ChartSection cs = settings.getChartSection(); + return cs != null ? cs.getSubtitle() : null; + } + + /** + * Returns the title of a chart. The return value depends on the existence + * of ChartSettings: if there are ChartSettings set, this method returns the + * chart title provided by those settings. Otherwise, this method returns + * getDefaultChartTitle(). + * + * @return the title of a chart. + */ + protected String getChartTitle(final CallContext context) { + final ChartSettings chartSettings = getChartSettings(); + + if (chartSettings != null) { + return getChartTitle(chartSettings); + } + + return getDefaultChartTitle(context); + } + + /** + * This method always returns null. Override it in subclasses that require + * subtitles. + * + * @return null. + */ + protected String getDefaultChartSubtitle(final CallContext context) { + // Override this method in subclasses + return null; + } + + /** Where to place the logo. */ + protected final String logoHPlace() { + final ChartSettings chartSettings = getChartSettings(); + if (chartSettings != null) { + final ChartSection cs = chartSettings.getChartSection(); + final String place = cs.getLogoHPlacement(); + + return place; + } + return "center"; + } + + /** Where to place the logo. */ + protected final String logoVPlace() { + final ChartSettings chartSettings = getChartSettings(); + if (chartSettings != null) { + final ChartSection cs = chartSettings.getChartSection(); + final String place = cs.getLogoVPlacement(); + + return place; + } + return "top"; + } + + /** Return the logo id from settings. */ + private String showLogo(final ChartSettings chartSettings) { + if (chartSettings != null) { + final ChartSection cs = chartSettings.getChartSection(); + final String logo = cs.getDisplayLogo(); + + return logo; + } + return "none"; + } + + /** + * This method is used to determine if a logo should be added to the plot. + * + * @return logo name (null if none). + */ + protected final String showLogo() { + final ChartSettings chartSettings = getChartSettings(); + return showLogo(chartSettings); + } + + /** + * This method is used to determine if the resulting chart should display + * grid lines or not. <b>Note: this method always returns true!</b> + * + * @return true, if the chart should display grid lines, otherwise false. + */ + protected final boolean isGridVisible() { + return true; + } + + protected final void addAnnotationsToRenderer(final XYPlot plot) { + + final AnnotationRenderer annotationRenderer = new AnnotationRenderer(getChartSettings(), this.datasets, DEFAULT_FONT_NAME); + annotationRenderer.addAnnotationsToRenderer(plot, this.annotations); + + doAddFurtherAnnotations(plot, this.annotations); + } + + /** + * Allow further annotation processing, override to implement. + * + * Does nothing by default. + */ + protected void doAddFurtherAnnotations(final XYPlot plot, final List<RiverAnnotation> annotations) { + + } } \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/AnnotationRenderer.java Tue Jun 05 19:21:16 2018 +0200 @@ -0,0 +1,352 @@ +/** 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.exports; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; + +import org.apache.log4j.Logger; +import org.dive4elements.river.jfree.AxisDataset; +import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation; +import org.dive4elements.river.jfree.RiverAnnotation; +import org.dive4elements.river.jfree.StickyAxisAnnotation; +import org.dive4elements.river.themes.LineStyle; +import org.dive4elements.river.themes.TextStyle; +import org.dive4elements.river.themes.ThemeDocument; +import org.jfree.chart.LegendItem; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.annotations.XYLineAnnotation; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.XYItemRenderer; +import org.jfree.ui.TextAnchor; + +/** + * @author Gernot Belger + */ +public final class AnnotationRenderer { + + private static final Logger log = Logger.getLogger(AnnotationRenderer.class); + + private static float ANNOTATIONS_AXIS_OFFSET = 0.02f; + + private final ChartSettings settings; + + private final Map<Integer, AxisDataset> datasets; + + private final String fontName; + + public AnnotationRenderer(final ChartSettings settings, final Map<Integer, AxisDataset> datasets, final String fontName) { + this.settings = settings; + this.datasets = datasets; + this.fontName = fontName; + } + + /** + * Add annotations (Sticky, Text and hyk zones) to a plot. + * + * @param annotations + * Annotations to add + * @param plot + * XYPlot to add annotations to. + * @param settings + * ChartSettings object for settings. + * @param datasets + * Map of axis index and datasets + */ + public final void addAnnotationsToRenderer(final XYPlot plot, final List<RiverAnnotation> annotations) { + if (annotations == null || annotations.isEmpty()) { + log.debug("addAnnotationsToRenderer: no annotations."); + return; + } + + // OPTMIMIZE: Pre-calculate positions + final ChartArea area = new ChartArea(plot.getDomainAxis(0), plot.getRangeAxis()); + + // Walk over all Annotation sets. + for (final RiverAnnotation fa : annotations) { + + // Access text styling, if any. + final ThemeDocument theme = fa.getTheme(); + TextStyle textStyle = null; + LineStyle lineStyle = null; + + // Get Theming information and add legend item. + if (theme != null) { + textStyle = theme.parseComplexTextStyle(); + lineStyle = theme.parseComplexLineStyle(); + if (fa.getLabel() != null) { + // Legend handling, maybe misplaced? + final LegendItemCollection lic = new LegendItemCollection(); + LegendItemCollection old = plot.getFixedLegendItems(); + + Color color = theme.parseLineColorField(); + if (color == null) { + color = Color.BLACK; + } + + Color textColor = theme.parseTextColor(); + if (textColor == null) { + textColor = Color.BLACK; + } + + final LegendItem newItem = new LegendItem(fa.getLabel(), color); + + final LegendSection ls = this.settings != null ? this.settings.getLegendSection() : null; + + final Integer size = ls != null ? ls.getFontSize() : null; + + newItem.setLabelFont(new Font(this.fontName, Font.PLAIN, size)); + + newItem.setLabelPaint(textColor); + + lic.add(newItem); + // (Re-)Add prior legend entries. + if (old != null) { + old.addAll(lic); + } else { + old = lic; + } + plot.setFixedLegendItems(old); + } + } + + // The 'Sticky' Annotations (at axis, with line and text). + for (final StickyAxisAnnotation sta : fa.getAxisTextAnnotations()) { + addStickyAnnotation(sta, plot, area, lineStyle, textStyle, theme, this.datasets.get(new Integer(sta.getAxisSymbol()))); + } + + // Other Text Annotations (e.g. labels of (manual) points). + for (final XYTextAnnotation ta : fa.getTextAnnotations()) { + // Style the text. + if (textStyle != null) { + textStyle.apply(ta); + } + ta.setY(area.above(0.05d, ta.getY())); + plot.getRenderer().addAnnotation(ta, org.jfree.ui.Layer.FOREGROUND); + } + } + } + + /** + * Add a text and a line annotation. + * + * @param area + * convenience to determine positions in plot. + * @param theme + * (optional) theme document + */ + private void addStickyAnnotation(final StickyAxisAnnotation annotation, final XYPlot plot, final ChartArea area, final LineStyle lineStyle, + final TextStyle textStyle, final ThemeDocument theme, final AxisDataset dataset) { + // OPTIMIZE pre-calculate area-related values + final float TEXT_OFF = 0.03f; + + XYLineAnnotation lineAnnotation = null; + XYTextAnnotation textAnnotation = null; + + final int axisIndex = annotation.getAxisSymbol(); + XYItemRenderer renderer = null; + if (dataset != null && dataset.getDatasets().length > 0) { + renderer = plot.getRendererForDataset(dataset.getDatasets()[0]); + } else { + renderer = plot.getRenderer(); + } + + if (annotation.atX()) { + textAnnotation = new CollisionFreeXYTextAnnotation(annotation.getText(), annotation.getPos(), area.ofGround(TEXT_OFF)); + // OPTIMIZE externalize the calculation involving PI. + // textAnnotation.setRotationAngle(270f*Math.PI/180f); + lineAnnotation = createGroundStickAnnotation(area, annotation.getPos(), lineStyle); + textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT); + textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT); + } else { + // Stick to the "right" (opposed to left) Y-Axis. + if (axisIndex != 0 && plot.getRangeAxis(axisIndex) != null) { + // OPTIMIZE: Pass a different area to this function, + // do the adding to renderer outside (let this + // function return the annotations). + // Note that this path is travelled rarely. + textAnnotation = new CollisionFreeXYTextAnnotation(annotation.getText(), area.ofRight(TEXT_OFF), annotation.getPos()); + textAnnotation.setRotationAnchor(TextAnchor.CENTER_RIGHT); + textAnnotation.setTextAnchor(TextAnchor.CENTER_RIGHT); + lineAnnotation = createRightStickAnnotation(area, annotation.getPos(), lineStyle); + + // hit-lines for duration curve + final ChartArea area2 = new ChartArea(plot.getDomainAxis(), plot.getRangeAxis(axisIndex)); + if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { + // New line annotation to hit curve. + if (theme.parseShowVerticalLine()) { + final XYLineAnnotation hitLineAnnotation = createStickyLineAnnotation(StickyAxisAnnotation.SimpleAxis.X_AXIS, annotation.getHitPoint(), + annotation.getPos(), + // annotation.getHitPoint(), + area2, lineStyle); + renderer.addAnnotation(hitLineAnnotation, org.jfree.ui.Layer.BACKGROUND); + } + if (theme.parseShowHorizontalLine()) { + final XYLineAnnotation lineBackAnnotation = createStickyLineAnnotation(StickyAxisAnnotation.SimpleAxis.Y_AXIS2, annotation.getPos(), + annotation.getHitPoint(), area2, lineStyle); + renderer.addAnnotation(lineBackAnnotation, org.jfree.ui.Layer.BACKGROUND); + } + } + } else { // Stick to the left y-axis. + textAnnotation = new CollisionFreeXYTextAnnotation(annotation.getText(), area.ofLeft(TEXT_OFF), annotation.getPos()); + textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT); + textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT); + lineAnnotation = createLeftStickAnnotation(area, annotation.getPos(), lineStyle); + if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { + // New line annotation to hit curve. + if (theme.parseShowHorizontalLine()) { + final XYLineAnnotation hitLineAnnotation = createStickyLineAnnotation(StickyAxisAnnotation.SimpleAxis.Y_AXIS, annotation.getPos(), + annotation.getHitPoint(), area, lineStyle); + renderer.addAnnotation(hitLineAnnotation, org.jfree.ui.Layer.BACKGROUND); + } + if (theme.parseShowVerticalLine()) { + final XYLineAnnotation lineBackAnnotation = createStickyLineAnnotation(StickyAxisAnnotation.SimpleAxis.X_AXIS, annotation.getHitPoint(), + annotation.getPos(), area, lineStyle); + renderer.addAnnotation(lineBackAnnotation, org.jfree.ui.Layer.BACKGROUND); + } + } + } + } + + // Style the text. + if (textStyle != null) { + textStyle.apply(textAnnotation); + } + + // Add the Annotations to renderer. + renderer.addAnnotation(textAnnotation, org.jfree.ui.Layer.FOREGROUND); + renderer.addAnnotation(lineAnnotation, org.jfree.ui.Layer.FOREGROUND); + } + + public final void addYAnnotationsToRenderer(final XYPlot plot, final SortedMap<Integer, RiverAnnotation> yAnnotations) { + final List<RiverAnnotation> annotations = new ArrayList<>(); + + for (final Map.Entry<Integer, RiverAnnotation> entry : yAnnotations.entrySet()) { + final int axis = entry.getKey(); + final AxisDataset dataset = this.datasets.get(new Integer(axis)); + + if (dataset == null || dataset.getRange() == null) { + log.warn("No dataset available and active for axis " + axis); + } else { + final RiverAnnotation ya = entry.getValue(); + for (final StickyAxisAnnotation sta : ya.getAxisTextAnnotations()) { + sta.setAxisSymbol(axis); + } + annotations.add(ya); + } + } + + addAnnotationsToRenderer(plot, annotations); + } + + /** + * Create annotation that sticks to "ground" (X) axis. + * + * @param area + * helper to calculate coordinates + * @param pos + * one-dimensional position (distance from axis) + * @param lineStyle + * the line style to use for the line. + */ + private XYLineAnnotation createGroundStickAnnotation(final ChartArea area, final float pos, final LineStyle lineStyle) { + if (lineStyle != null) + return new XYLineAnnotation(pos, area.atGround(), pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET), new BasicStroke(lineStyle.getWidth()), + lineStyle.getColor()); + + return new XYLineAnnotation(pos, area.atGround(), pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET)); + } + + /** + * Create annotation that sticks to the second Y axis ("right"). + * + * @param area + * helper to calculate coordinates + * @param pos + * one-dimensional position (distance from axis) + * @param lineStyle + * the line style to use for the line. + */ + private XYLineAnnotation createRightStickAnnotation(final ChartArea area, final float pos, final LineStyle lineStyle) { + if (lineStyle != null) + return new XYLineAnnotation(area.atRight(), pos, area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos, new BasicStroke(lineStyle.getWidth()), + lineStyle.getColor()); + + return new XYLineAnnotation(area.atRight(), pos, area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos); + } + + /** + * Create annotation that sticks to the first Y axis ("left"). + * + * @param area + * helper to calculate coordinates + * @param pos + * one-dimensional position (distance from axis) + * @param lineStyle + * the line style to use for the line. + */ + private XYLineAnnotation createLeftStickAnnotation(final ChartArea area, final float pos, final LineStyle lineStyle) { + if (lineStyle != null) + return new XYLineAnnotation(area.atLeft(), pos, area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos, new BasicStroke(lineStyle.getWidth()), + lineStyle.getColor()); + + return new XYLineAnnotation(area.atLeft(), pos, area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos); + } + + /** + * Create a line from a axis to a given point. + * + * @param axis + * The "simple" axis. + * @param fromD1 + * from-location in first dimension. + * @param toD2 + * to-location in second dimension. + * @param area + * helper to calculate offsets. + * @param lineStyle + * optional line style. + */ + public static XYLineAnnotation createStickyLineAnnotation(final StickyAxisAnnotation.SimpleAxis axis, final float fromD1, final float toD2, + final ChartArea area, final LineStyle lineStyle) { + double anchorX1 = 0d, anchorX2 = 0d, anchorY1 = 0d, anchorY2 = 0d; + switch (axis) { + case X_AXIS: + anchorX1 = fromD1; + anchorX2 = fromD1; + anchorY1 = area.atGround(); + anchorY2 = toD2; + break; + case Y_AXIS: + anchorX1 = area.atLeft(); + anchorX2 = toD2; + anchorY1 = fromD1; + anchorY2 = fromD1; + break; + case Y_AXIS2: + anchorX1 = area.atRight(); + anchorX2 = toD2; + anchorY1 = fromD1; + anchorY2 = fromD1; + break; + } + + if (lineStyle != null) + return new XYLineAnnotation(anchorX1, anchorY1, anchorX2, anchorY2, new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); + + return new XYLineAnnotation(anchorX1, anchorY1, anchorX2, anchorY2); + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/AxisSection.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/AxisSection.java Tue Jun 05 19:21:16 2018 +0200 @@ -85,8 +85,8 @@ } - public Boolean isFixed() { - return getBooleanValue(FIXATION_ATTR); + public boolean isFixed() { + return getBooleanValue(FIXATION_ATTR, false); }
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartExportHelper.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartExportHelper.java Tue Jun 05 19:21:16 2018 +0200 @@ -495,17 +495,4 @@ return origin; } - - - public static String createMetadataSubtitle(Artifact artifact, final CallContext context, final String riverName) { - - final String version = FLYS.VERSION; - final String user = CalculationUtils.findArtifactUser(context, artifact); - final Locale locale = Resources.getLocale(context.getMeta()); - final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT, locale); - final String dateText = df.format(new Date()); - - return Resources.getMsg(context.getMeta(), "chart.subtitle.metadata", "default", version, user, dateText, riverName); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -8,66 +8,18 @@ package org.dive4elements.river.exports; -import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.artifactdatabase.state.Settings; -import org.dive4elements.artifacts.Artifact; -import org.dive4elements.artifacts.ArtifactNamespaceContext; -import org.dive4elements.artifacts.CallContext; -import org.dive4elements.artifacts.CallMeta; -import org.dive4elements.artifacts.PreferredLocale; -import org.dive4elements.artifacts.common.utils.XMLUtils; - -import org.dive4elements.river.artifacts.access.RiverAccess; -import org.dive4elements.river.artifacts.access.RangeAccess; -import org.dive4elements.river.artifacts.D4EArtifact; -import org.dive4elements.river.artifacts.resources.Resources; -import org.dive4elements.river.collections.D4EArtifactCollection; -import org.dive4elements.river.jfree.Bounds; -import org.dive4elements.river.jfree.DoubleBounds; -import org.dive4elements.river.jfree.EnhancedLineAndShapeRenderer; -import org.dive4elements.river.jfree.RiverAnnotation; -import org.dive4elements.river.jfree.StableXYDifferenceRenderer; -import org.dive4elements.river.jfree.Style; -import org.dive4elements.river.jfree.StyledAreaSeriesCollection; -import org.dive4elements.river.jfree.StyledSeries; -import org.dive4elements.river.jfree.AxisDataset; -import org.dive4elements.river.themes.ThemeDocument; - -import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Font; -import java.awt.Paint; -import java.awt.Stroke; -import java.awt.TexturePaint; -import java.awt.geom.Rectangle2D; -import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.SortedMap; -import java.util.TreeMap; - -import javax.xml.xpath.XPathConstants; -import org.apache.log4j.Logger; -import org.jfree.chart.JFreeChart; -import org.jfree.chart.LegendItem; -import org.jfree.chart.LegendItemCollection; +import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.jfree.RiverAnnotation; +import org.dive4elements.river.themes.ThemeDocument; import org.jfree.chart.axis.NumberAxis; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; -import org.jfree.chart.title.TextTitle; import org.jfree.data.Range; -import org.jfree.data.general.Series; -import org.jfree.data.xy.XYDataset; -import org.jfree.ui.RectangleInsets; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import org.dive4elements.river.utils.Formatter; /** * The base class for chart creation. It should provide some basic things that @@ -82,57 +34,6 @@ */ public abstract class ChartGenerator extends AbstractChartGenerator { - private static Logger log = Logger.getLogger(ChartGenerator.class); - - public static final int DEFAULT_CHART_WIDTH = 600; - public static final int DEFAULT_CHART_HEIGHT = 400; - public static final String DEFAULT_CHART_FORMAT = "png"; - public static final Color DEFAULT_GRID_COLOR = Color.GRAY; - public static final float DEFAULT_GRID_LINE_WIDTH = 0.3f; - public static final int DEFAULT_FONT_SIZE = 12; - public static final String DEFAULT_FONT_NAME = "Tahoma"; - - protected static float ANNOTATIONS_AXIS_OFFSET = 0.02f; - - public static final String XPATH_CHART_SIZE = - "/art:action/art:attributes/art:size"; - - public static final String XPATH_CHART_FORMAT = - "/art:action/art:attributes/art:format/@art:value"; - - public static final String XPATH_CHART_X_RANGE = - "/art:action/art:attributes/art:xrange"; - - public static final String XPATH_CHART_Y_RANGE = - "/art:action/art:attributes/art:yrange"; - - - /** The document of the incoming out() request.*/ - protected Document request; - - /** The output stream where the data should be written to.*/ - protected OutputStream out; - - /** The CallContext object.*/ - protected CallContext context; - - protected D4EArtifactCollection collection; - - /** Artifact that is used to decorate the chart with meta information.*/ - protected Artifact master; - - /** The settings that should be used during output creation.*/ - protected Settings settings; - - /** Map of datasets ("index"). */ - protected SortedMap<Integer, AxisDataset> datasets; - - /** List of annotations to insert in plot. */ - protected List<RiverAnnotation> annotations = - new ArrayList<RiverAnnotation>(); - - protected String outName; - /** * A mini interface that allows to walk over the YAXIS enums defined in * subclasses. @@ -145,158 +46,8 @@ } // end of YAxisWalker interface - /** - * Default constructor that initializes internal data structures. - */ - public ChartGenerator() { - datasets = new TreeMap<>(); - } - - @Override - protected final D4EArtifact getArtifact() { - // FIXME: should already made sure when this member is set - return (D4EArtifact) this.master; - } - - @Override - protected final CallContext getContext() { - return this.context; - } - - @Override - protected final Document getRequest() { - return this.request; - } - - @Override - public void setup(Object config) { - log.debug("ChartGenerator.setup"); - } - - /** - * Adds annotations to list. The given annotation will be visible. - */ - public void addAnnotations(RiverAnnotation annotation) { - annotations.add(annotation); - } - - - /** - * This method needs to be implemented by concrete subclasses to create new - * instances of JFreeChart. - * - * @return a new instance of a JFreeChart. - */ - public abstract JFreeChart generateChart(); - - - /** For every outable (i.e. facets), this function is - * called and handles the data accordingly. */ - @Override - public abstract void doOut( - ArtifactAndFacet bundle, - ThemeDocument attr, - boolean visible); - - protected abstract YAxisWalker getYAxisWalker(); - - protected abstract Series getSeriesOf(XYDataset dataset, int idx); - - /** - * Returns the default title of a chart. - * - * @return the default title of a chart. - */ - protected abstract String getDefaultChartTitle(); - - - /** - * Returns the default X-Axis label of a chart. - * - * @return the default X-Axis label of a chart. - */ - protected abstract String getDefaultXAxisLabel(); - - - /** - * This method is called to retrieve the default label for an Y axis at - * position <i>pos</i>. - * - * @param pos The position of an Y axis. - * - * @return the default Y axis label at position <i>pos</i>. - */ - protected abstract String getDefaultYAxisLabel(int pos); - - - /** - * This method is used to create new AxisDataset instances which may differ - * in concrete subclasses. - * - * @param idx The index of an axis. - */ - protected abstract AxisDataset createAxisDataset(int idx); - - - /** - * Combines the ranges of the X axis at index <i>idx</i>. - * - * @param bounds A new Bounds. - * @param idx The index of the X axis that should be comined with - * <i>range</i>. - */ - protected abstract void combineXBounds(Bounds bounds, int idx); - - - /** - * Combines the ranges of the Y axis at index <i>idx</i>. - * - * @param bounds A new Bounds. - * @param index The index of the Y axis that should be comined with. - * <i>range</i>. - */ - protected abstract void combineYBounds(Bounds bounds, int index); - - - /** - * This method is used to determine the ranges for axes at a given index. - * - * @param index The index of the axes at the plot. - * - * @return a Range[] with [xrange, yrange]; - */ - public abstract Range[] getRangesForAxis(int index); - - public abstract Bounds getXBounds(int axis); - - protected abstract void setXBounds(int axis, Bounds bounds); - - public abstract Bounds getYBounds(int axis); - - protected abstract void setYBounds(int axis, Bounds bounds); - - - /** - * This method retrieves the chart subtitle by calling getChartSubtitle() - * and adds it as TextTitle to the chart. - * The default implementation of getChartSubtitle() returns the same - * as getDefaultChartSubtitle() which must be implemented by derived - * classes. If you want to add multiple subtitles to the chart override - * this method and add your subtitles manually. - * - * @param chart The JFreeChart chart object. - */ - protected void addSubtitles(JFreeChart chart) { - String subtitle = getChartSubtitle(); - - if (subtitle != null && subtitle.length() > 0) { - chart.addSubtitle(new TextTitle(subtitle)); - } - } - - /** * Register annotations like MainValues for later plotting * @@ -329,148 +80,21 @@ } } - - /** - * Generate chart. - */ - @Override - public void generate() - throws IOException - { - log.debug("ChartGenerator.generate"); - - JFreeChart chart = generateChart(); - - String format = getFormat(); - int[] size = getSize(); - - if (size == null) { - size = getExportDimension(); - } - - context.putContextValue("chart.width", size[0]); - context.putContextValue("chart.height", size[1]); - - if (format.equals(ChartExportHelper.FORMAT_PNG)) { - context.putContextValue("chart.image.format", "png"); - - ChartExportHelper.exportImage( - out, - chart, - context); - } - else if (format.equals(ChartExportHelper.FORMAT_PDF)) { - preparePDFContext(context); - - ChartExportHelper.exportPDF( - out, - chart, - context); - } - else if (format.equals(ChartExportHelper.FORMAT_SVG)) { - prepareSVGContext(context); - - ChartExportHelper.exportSVG( - out, - chart, - context); - } - else if (format.equals(ChartExportHelper.FORMAT_CSV)) { - context.putContextValue("chart.image.format", "csv"); - - ChartExportHelper.exportCSV( - out, - chart, - context); - } - } - - @Override - public void init( - String outName, - Document request, - OutputStream out, - CallContext context - ) { - log.debug("ChartGenerator.init"); - - this.outName = outName; - this.request = request; - this.out = out; - this.context = context; - } - - - /** Sets the master artifact. */ - @Override - public void setMasterArtifact(Artifact master) { - this.master = master; - } - - - /** - * Gets the master artifact. - * @return the master artifact. - */ - public Artifact getMaster() { - return master; - } - - - /** Sets the collection. */ - @Override - public void setCollection(D4EArtifactCollection collection) { - this.collection = collection; + protected void doGenerate(CallContext context, OutputStream out, String outName) throws IOException { + generateImage(context); } - - @Override - public void setSettings(Settings settings) { - this.settings = settings; - } - - - /** - * Returns instance of <i>ChartSettings</i> with a chart specific section - * but with no axes settings. - * - * @return an instance of <i>ChartSettings</i>. - */ - @Override - public Settings getSettings() { - if (this.settings != null) { - return this.settings; - } - - ChartSettings settings = new ChartSettings(); - - ChartSection chartSection = buildChartSection(); - LegendSection legendSection = buildLegendSection(); - ExportSection exportSection = buildExportSection(); - - settings.setChartSection(chartSection); - settings.setLegendSection(legendSection); - settings.setExportSection(exportSection); - - List<AxisSection> axisSections = buildAxisSections(); - for (AxisSection axisSection: axisSections) { - settings.addAxisSection(axisSection); - } - - return settings; - } - - /** * Creates a new <i>ChartSection</i>. * * @return a new <i>ChartSection</i>. */ - protected ChartSection buildChartSection() { + @Override + protected ChartSection buildChartSection(final CallContext context) { ChartSection chartSection = new ChartSection(); - chartSection.setTitle(getChartTitle()); - chartSection.setSubtitle(getChartSubtitle()); + chartSection.setTitle(getChartTitle(context)); + chartSection.setSubtitle(getChartSubtitle(context)); chartSection.setDisplayGrid(isGridVisible()); chartSection.setDisplayLogo(showLogo()); chartSection.setLogoVPlacement(logoVPlace()); @@ -478,78 +102,6 @@ return chartSection; } - - /** - * Creates a new <i>LegendSection</i>. - * - * @return a new <i>LegendSection</i>. - */ - protected LegendSection buildLegendSection() { - LegendSection legendSection = new LegendSection(); - legendSection.setVisibility(isLegendVisible()); - legendSection.setFontSize(getLegendFontSize()); - legendSection.setAggregationThreshold(10); - return legendSection; - } - - - /** - * Creates a new <i>ExportSection</i> with default values <b>WIDTH=600</b> - * and <b>HEIGHT=400</b>. - * - * @return a new <i>ExportSection</i>. - */ - protected ExportSection buildExportSection() { - ExportSection exportSection = new ExportSection(); - exportSection.setWidth(600); - exportSection.setHeight(400); - return exportSection; - } - - - /** - * Create list of Sections that contains all axes of the chart (including - * X and Y axes). - * - * @return a list of Sections for each axis in this chart. - */ - protected List<AxisSection> buildAxisSections() { - List<AxisSection> axisSections = new ArrayList<AxisSection>(); - - axisSections.addAll(buildXAxisSections()); - axisSections.addAll(buildYAxisSections()); - - return axisSections; - } - - - /** - * Creates a new Section for chart's X axis. - * - * @return a List that contains a Section for the X axis. - */ - protected List<AxisSection> buildXAxisSections() { - List<AxisSection> axisSections = new ArrayList<AxisSection>(); - - String identifier = "X"; - - AxisSection axisSection = new AxisSection(); - axisSection.setIdentifier(identifier); - axisSection.setLabel(getXAxisLabel()); - axisSection.setFontSize(14); - axisSection.setFixed(false); - - // XXX We are able to find better default ranges that [0,0], but the Y - // axes currently have no better ranges set. - axisSection.setUpperRange(0d); - axisSection.setLowerRange(0d); - - axisSections.add(axisSection); - - return axisSections; - } - - /** * Creates a list of Section for the chart's Y axes. This method makes use * of <i>getYAxisWalker</i> to be able to access all Y axes defined in @@ -557,8 +109,9 @@ * * @return a list of Y axis sections. */ - protected List<AxisSection> buildYAxisSections() { - List<AxisSection> axisSections = new ArrayList<AxisSection>(); + @Override + protected final List<AxisSection> buildYAxisSections() { + List<AxisSection> axisSections = new ArrayList<>(); YAxisWalker walker = getYAxisWalker(); for (int i = 0, n = walker.length(); i < n; i++) { @@ -581,127 +134,6 @@ return axisSections; } - - /** - * Returns the <i>settings</i> as <i>ChartSettings</i>. - * - * @return the <i>settings</i> as <i>ChartSettings</i> or null, if - * <i>settings</i> is not an instance of <i>ChartSettings</i>. - */ - public ChartSettings getChartSettings() { - if (settings instanceof ChartSettings) { - return (ChartSettings) settings; - } - - return null; - } - - - /** - * Returns the chart title provided by <i>settings</i>. - * - * @param settings A ChartSettings object. - * - * @return the title provided by <i>settings</i> or null if no - * <i>ChartSection</i> is provided by <i>settings</i>. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public String getChartTitle(ChartSettings settings) { - ChartSection cs = settings.getChartSection(); - return cs != null ? cs.getTitle() : null; - } - - - /** - * Returns the chart subtitle provided by <i>settings</i>. - * - * @param settings A ChartSettings object. - * - * @return the subtitle provided by <i>settings</i> or null if no - * <i>ChartSection</i> is provided by <i>settings</i>. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public String getChartSubtitle(ChartSettings settings) { - ChartSection cs = settings.getChartSection(); - return cs != null ? cs.getSubtitle() : null; - } - - - /** - * Returns a boolean object that determines if the chart grid should be - * visible or not. This information needs to be provided by <i>settings</i>, - * otherweise the default is true. - * - * @param settings A ChartSettings object. - * - * @return true, if the chart grid should be visible otherwise false. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public boolean isGridVisible(ChartSettings settings) { - ChartSection cs = settings.getChartSection(); - Boolean displayGrid = cs.getDisplayGrid(); - - return displayGrid != null ? displayGrid : true; - } - - - /** - * Returns a boolean object that determines if the chart legend should be - * visible or not. This information needs to be provided by <i>settings</i>, - * otherwise the default is true. - * - * @param settings A ChartSettings object. - * - * @return true, if the chart legend should be visible otherwise false. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public boolean isLegendVisible(ChartSettings settings) { - LegendSection ls = settings.getLegendSection(); - Boolean displayLegend = ls.getVisibility(); - - return displayLegend != null ? displayLegend : true; - } - - - /** - * Returns the legend font size specified in <i>settings</i> or null if no - * <i>LegendSection</i> is provided by <i>settings</i>. - * - * @param settings A ChartSettings object. - * - * @return the legend font size or null. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public Integer getLegendFontSize(ChartSettings settings) { - LegendSection ls = settings.getLegendSection(); - return ls != null ? ls.getFontSize() : null; - } - - - /** - * Returns the title of a chart. The return value depends on the existence - * of ChartSettings: if there are ChartSettings set, this method returns the - * chart title provided by those settings. Otherwise, this method returns - * getDefaultChartTitle(). - * - * @return the title of a chart. - */ - protected String getChartTitle() { - ChartSettings chartSettings = getChartSettings(); - - if (chartSettings != null) { - return getChartTitle(chartSettings); - } - - return getDefaultChartTitle(); - } - - /** * Returns the subtitle of a chart. The return value depends on the * existence of ChartSettings: if there are ChartSettings set, this method @@ -710,171 +142,16 @@ * * @return the subtitle of a chart. */ - protected String getChartSubtitle() { + @Override + protected String getChartSubtitle(final CallContext context) { ChartSettings chartSettings = getChartSettings(); - if (chartSettings != null) { + if (chartSettings != null) return getChartSubtitle(chartSettings); - } - - return getDefaultChartSubtitle(); - } - - - /** - * This method always returns null. Override it in subclasses that require - * subtitles. - * - * @return null. - */ - protected String getDefaultChartSubtitle() { - // Override this method in subclasses - return null; - } - - - /** - * This method is used to determine, if the chart's legend is visible or - * not. If a <i>settings</i> instance is set, this instance determines the - * visibility otherwise, this method returns true as default if no - * <i>settings</i> is set. - * - * @return true, if the legend should be visible, otherwise false. - */ - protected boolean isLegendVisible() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings != null) { - return isLegendVisible(chartSettings); - } - - return true; - } - - - /** Where to place the logo. */ - protected String logoHPlace() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings != null) { - ChartSection cs = chartSettings.getChartSection(); - String place = cs.getLogoHPlacement(); - - return place; - } - return "center"; - } - - - /** Where to place the logo. */ - protected String logoVPlace() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings != null) { - ChartSection cs = chartSettings.getChartSection(); - String place = cs.getLogoVPlacement(); - - return place; - } - return "top"; - } - - - /** Return the logo id from settings. */ - protected String showLogo(ChartSettings chartSettings) { - if (chartSettings != null) { - ChartSection cs = chartSettings.getChartSection(); - String logo = cs.getDisplayLogo(); - - return logo; - } - return "none"; - } - - /** - * This method is used to determine if a logo should be added to the plot. - * - * @return logo name (null if none). - */ - protected String showLogo() { - ChartSettings chartSettings = getChartSettings(); - return showLogo(chartSettings); - } - - - /** - * This method is used to determine the font size of the chart's legend. If - * a <i>settings</i> instance is set, this instance determines the font - * size, otherwise this method returns 12 as default if no <i>settings</i> - * is set or if it doesn't provide a legend font size. - * - * @return a legend font size. - */ - protected int getLegendFontSize() { - Integer fontSize = null; - - ChartSettings chartSettings = getChartSettings(); - if (chartSettings != null) { - fontSize = getLegendFontSize(chartSettings); - } - - return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; - } - - - /** - * This method is used to determine if the resulting chart should display - * grid lines or not. <b>Note: this method always returns true!</b> - * - * @return true, if the chart should display grid lines, otherwise false. - */ - protected boolean isGridVisible() { - return true; + return getDefaultChartSubtitle(context); } - - /** - * Returns the X-Axis label of a chart. - * - * @return the X-Axis label of a chart. - */ - protected String getXAxisLabel() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings == null) { - return getDefaultXAxisLabel(); - } - - AxisSection as = chartSettings.getAxisSection("X"); - if (as != null) { - String label = as.getLabel(); - - if (label != null) { - return label; - } - } - - return getDefaultXAxisLabel(); - } - - - /** - * This method returns the font size for the X axis. If the font size is - * specified in ChartSettings (if <i>chartSettings</i> is set), this size is - * returned. Otherwise the default font size 12 is returned. - * - * @return the font size for the x axis. - */ - protected int getXAxisLabelFontSize() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings == null) { - return DEFAULT_FONT_SIZE; - } - - AxisSection as = chartSettings.getAxisSection("X"); - Integer fontSize = as.getFontSize(); - - return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; - } - - /** * This method returns the font size for an Y axis. If the font size is * specified in ChartSettings (if <i>chartSettings</i> is set), this size is @@ -899,31 +176,6 @@ return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; } - - /** - * This method returns the export dimension specified in ChartSettings as - * int array [width,height]. - * - * @return an int array with [width,height]. - */ - protected int[] getExportDimension() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings == null) { - return new int[] { 600, 400 }; - } - - ExportSection export = chartSettings.getExportSection(); - Integer width = export.getWidth(); - Integer height = export.getHeight(); - - if (width != null && height != null) { - return new int[] { width, height }; - } - - return new int[] { 600, 400 }; - } - - /** * Returns the Y-Axis label of a chart at position <i>pos</i>. * @@ -947,7 +199,17 @@ return getDefaultYAxisLabel(pos); } - + + /** + * This method is called to retrieve the default label for an Y axis at + * position <i>pos</i>. + * + * @param pos + * The position of an Y axis. + * + * @return the default Y axis label at position <i>pos</i>. + */ + protected abstract String getDefaultYAxisLabel(int pos); /** * This method searches for a specific axis in the <i>settings</i> if @@ -972,9 +234,7 @@ return null; } - Boolean fixed = as.isFixed(); - - if (fixed != null && fixed) { + if (as.isFixed()) { /* Only time series charts have time ranges so prefer those. */ if (axisId.equals("X")) { @@ -1002,486 +262,6 @@ return null; } - - /** - * Adds a new AxisDataset which contains <i>dataset</i> at index <i>idx</i>. - * - * @param dataset An XYDataset. - * @param idx The axis index. - * @param visible Determines, if the dataset should be visible or not. - */ - public void addAxisDataset(XYDataset dataset, int idx, boolean visible) { - if (dataset == null || idx < 0) { - return; - } - - AxisDataset axisDataset = getAxisDataset(idx); - - Bounds[] xyBounds = ChartHelper.getBounds(dataset); - - if (xyBounds == null) { - log.warn("Skip XYDataset for Axis (invalid ranges): " + idx); - return; - } - - if (visible) { - if (log.isDebugEnabled()) { - log.debug("Add new AxisDataset at index: " + idx); - log.debug("X extent: " + xyBounds[0]); - log.debug("Y extent: " + xyBounds[1]); - } - - axisDataset.addDataset(dataset); - } - - combineXBounds(xyBounds[0], 0); - combineYBounds(xyBounds[1], idx); - } - - - /** - * This method grants access to the AxisDatasets stored in <i>datasets</i>. - * If no AxisDataset exists for index <i>idx</i>, a new AxisDataset is - * created using <i>createAxisDataset()</i>. - * - * @param idx The index of the desired AxisDataset. - * - * @return an existing or new AxisDataset. - */ - public AxisDataset getAxisDataset(int idx) { - AxisDataset axisDataset = datasets.get(idx); - - if (axisDataset == null) { - axisDataset = createAxisDataset(idx); - datasets.put(idx, axisDataset); - } - - return axisDataset; - } - - - /** - * Adjust some Stroke/Grid parameters for <i>plot</i>. The chart - * <i>Settings</i> are applied in this method. - * - * @param plot The XYPlot which is adapted. - */ - protected void adjustPlot(XYPlot plot) { - Stroke gridStroke = new BasicStroke( - DEFAULT_GRID_LINE_WIDTH, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 3.0f, - new float[] { 3.0f }, - 0.0f); - - ChartSettings cs = getChartSettings(); - boolean isGridVisible = cs != null ? isGridVisible(cs) : true; - - plot.setDomainGridlineStroke(gridStroke); - plot.setDomainGridlinePaint(DEFAULT_GRID_COLOR); - plot.setDomainGridlinesVisible(isGridVisible); - - plot.setRangeGridlineStroke(gridStroke); - plot.setRangeGridlinePaint(DEFAULT_GRID_COLOR); - plot.setRangeGridlinesVisible(isGridVisible); - - plot.setAxisOffset(new RectangleInsets(0d, 0d, 0d, 0d)); - } - - - /** - * This helper mehtod is used to extract the current locale from instance - * vairable <i>context</i>. - * - * @return the current locale. - */ - protected Locale getLocale() { - CallMeta meta = context.getMeta(); - PreferredLocale[] prefs = meta.getLanguages(); - - int len = prefs != null ? prefs.length : 0; - - Locale[] locales = new Locale[len]; - - for (int i = 0; i < len; i++) { - locales[i] = prefs[i].getLocale(); - } - - return meta.getPreferredLocale(locales); - } - - - /** - * Look up \param key in i18n dictionary. - * @param key key for which to find i18nd version. - * @param def default, returned if lookup failed. - * @return value found in i18n dictionary, \param def if no value found. - */ - protected String msg(String key, String def) { - return Resources.getMsg(context.getMeta(), key, def); - } - - /** - * Look up \param key in i18n dictionary. - * @param key key for which to find i18nd version. - * @return value found in i18n dictionary, key itself if failed. - */ - protected String msg(String key) { - return Resources.getMsg(context.getMeta(), key, key); - } - - protected String msg(String key, Object[] args) { - return Resources.getMsg(context.getMeta(), key, key, args); - } - - protected String msg(String key, String def, Object[] args) { - return Resources.getMsg(context.getMeta(), key, def, args); - } - - /** - * Returns the size of a chart export as array which has been specified by - * the incoming request document. - * - * @return the size of a chart as [width, height] or null if no width or - * height are given in the request document. - */ - protected int[] getSize() { - int[] size = new int[2]; - - Element sizeEl = (Element)XMLUtils.xpath( - request, - XPATH_CHART_SIZE, - XPathConstants.NODE, - ArtifactNamespaceContext.INSTANCE); - - if (sizeEl != null) { - String uri = ArtifactNamespaceContext.NAMESPACE_URI; - - String w = sizeEl.getAttributeNS(uri, "width"); - String h = sizeEl.getAttributeNS(uri, "height"); - - if (w.length() > 0 && h.length() > 0) { - try { - size[0] = Integer.parseInt(w); - size[1] = Integer.parseInt(h); - } - catch (NumberFormatException nfe) { - log.warn("Wrong values for chart width/height."); - } - } - } - - return size[0] > 0 && size[1] > 0 ? size : null; - } - - - /** - * This method returns the format specified in the <i>request</i> document - * or <i>DEFAULT_CHART_FORMAT</i> if no format is specified in - * <i>request</i>. - * - * @return the format used to export this chart. - */ - protected String getFormat() { - String format = (String) XMLUtils.xpath( - request, - XPATH_CHART_FORMAT, - XPathConstants.STRING, - ArtifactNamespaceContext.INSTANCE); - - return format == null || format.length() == 0 - ? DEFAULT_CHART_FORMAT - : format; - } - - /** - * Returns the X-Axis range as String array from request document. - * If the (x|y)range elements are not found in request document, return - * null (i.e. not zoomed). - * - * @return a String array with [lower, upper], null if not in document. - */ - protected String[] getDomainAxisRangeFromRequest() { - Element xrange = (Element)XMLUtils.xpath( - request, - XPATH_CHART_X_RANGE, - XPathConstants.NODE, - ArtifactNamespaceContext.INSTANCE); - - if (xrange == null) { - return null; - } - - String uri = ArtifactNamespaceContext.NAMESPACE_URI; - - String lower = xrange.getAttributeNS(uri, "from"); - String upper = xrange.getAttributeNS(uri, "to"); - - return new String[] { lower, upper }; - } - - - /** Returns null if the (x|y)range-element was not found in - * request document. - * This usally means that the axis are not manually zoomed, i.e. showing - * full data extent. */ - protected String[] getValueAxisRangeFromRequest() { - Element yrange = (Element)XMLUtils.xpath( - request, - XPATH_CHART_Y_RANGE, - XPathConstants.NODE, - ArtifactNamespaceContext.INSTANCE); - - if (yrange == null) { - return null; - } - - - String uri = ArtifactNamespaceContext.NAMESPACE_URI; - - String lower = yrange.getAttributeNS(uri, "from"); - String upper = yrange.getAttributeNS(uri, "to"); - - return new String[] { lower, upper }; - } - - - /** - * Returns the default size of a chart export as array. - * - * @return the default size of a chart as [width, height]. - */ - protected int[] getDefaultSize() { - return new int[] { DEFAULT_CHART_WIDTH, DEFAULT_CHART_HEIGHT }; - } - - - /** - * Add datasets stored in instance variable <i>datasets</i> to plot. - * <i>datasets</i> actually stores instances of AxisDataset, so each of this - * datasets is mapped to a specific axis as well. - * - * @param plot plot to add datasets to. - */ - protected void addDatasets(XYPlot plot) { - log.debug("addDatasets()"); - - // AxisDatasets are sorted, but some might be empty. - // Thus, generate numbering on the fly. - int axisIndex = 0; - int datasetIndex = 0; - - for (Map.Entry<Integer, AxisDataset> entry: datasets.entrySet()) { - if (!entry.getValue().isEmpty()) { - // Add axis and range information. - AxisDataset axisDataset = entry.getValue(); - NumberAxis axis = createYAxis(entry.getKey()); - - plot.setRangeAxis(axisIndex, axis); - - if (axis.getAutoRangeIncludesZero()) { - axisDataset.setRange( - Range.expandToInclude(axisDataset.getRange(), 0d)); - } - - setYBounds( - axisIndex, expandPointRange(axisDataset.getRange())); - - // Add contained datasets, mapping to axis. - for (XYDataset dataset: axisDataset.getDatasets()) { - plot.setDataset(datasetIndex, dataset); - plot.mapDatasetToRangeAxis(datasetIndex, axisIndex); - - applyThemes(plot, dataset, - datasetIndex, - axisDataset.isArea(dataset)); - - datasetIndex++; - } - - axisDataset.setPlotAxisIndex(axisIndex); - axisIndex++; - } - } - } - - - /** - * @param idx "index" of dataset/series (first dataset to be drawn has - * index 0), correlates with renderer index. - * @param isArea true if the series describes an area and shall be rendered - * as such. - */ - protected void applyThemes( - XYPlot plot, - XYDataset series, - int idx, - boolean isArea - ) { - if (isArea) { - applyAreaTheme(plot, (StyledAreaSeriesCollection) series, idx); - } - else { - applyLineTheme(plot, series, idx); - } - } - - - /** - * This method applies the themes defined in the series itself. Therefore, - * <i>StyledXYSeries.applyTheme()</i> is called, which modifies the renderer - * for the series. - * - * @param plot The plot. - * @param dataset The XYDataset which needs to support Series objects. - * @param idx The index of the renderer / dataset. - */ - protected void applyLineTheme(XYPlot plot, XYDataset dataset, int idx) { - log.debug("Apply LineTheme for dataset at index: " + idx); - - LegendItemCollection lic = new LegendItemCollection(); - LegendItemCollection anno = plot.getFixedLegendItems(); - - Font legendFont = createLegendLabelFont(); - - XYLineAndShapeRenderer renderer = createRenderer(plot, idx); - - for (int s = 0, num = dataset.getSeriesCount(); s < num; s++) { - Series series = getSeriesOf(dataset, s); - - if (series instanceof StyledSeries) { - Style style = ((StyledSeries) series).getStyle(); - style.applyTheme(renderer, s); - } - - // special case: if there is just one single item, we need to enable - // points for this series, otherwise we would not see anything in - // the chart area. - if (series.getItemCount() == 1) { - renderer.setSeriesShapesVisible(s, true); - } - - LegendItem legendItem = renderer.getLegendItem(idx, s); - if (legendItem.getLabel().endsWith(" ") || - legendItem.getLabel().endsWith("interpol")) { - legendItem = null; - } - - if (legendItem != null) { - legendItem.setLabelFont(legendFont); - lic.add(legendItem); - } - else { - log.warn("Could not get LegentItem for renderer: " - + idx + ", series-idx " + s); - } - } - - if (anno != null) { - lic.addAll(anno); - } - - plot.setFixedLegendItems(lic); - - plot.setRenderer(idx, renderer); - } - - - /** - * @param plot The plot. - * @param area A StyledAreaSeriesCollection object. - * @param idx The index of the dataset. - */ - protected void applyAreaTheme( - XYPlot plot, - StyledAreaSeriesCollection area, - int idx - ) { - LegendItemCollection lic = new LegendItemCollection(); - LegendItemCollection anno = plot.getFixedLegendItems(); - - Font legendFont = createLegendLabelFont(); - - log.debug("Registering an 'area'renderer at idx: " + idx); - - StableXYDifferenceRenderer dRenderer = - new StableXYDifferenceRenderer(); - - if (area.getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) { - dRenderer.setPositivePaint(createTransparentPaint()); - } - - plot.setRenderer(idx, dRenderer); - - area.applyTheme(dRenderer); - - // i18n - dRenderer.setAreaLabelNumberFormat( - Formatter.getFormatter(context.getMeta(), 2, 4)); - - dRenderer.setAreaLabelTemplate(Resources.getMsg( - context.getMeta(), "area.label.template", "Area=%sm2")); - - LegendItem legendItem = dRenderer.getLegendItem(idx, 0); - if (legendItem != null) { - legendItem.setLabelFont(legendFont); - lic.add(legendItem); - } - else { - log.warn("Could not get LegentItem for renderer: " - + idx + ", series-idx " + 0); - } - - if (anno != null) { - lic.addAll(anno); - } - - plot.setFixedLegendItems(lic); - } - - - /** - * Expands a given range if it collapses into one point. - * - * @param range Range to be expanded if upper == lower bound. - * - * @return Bounds of point plus 5 percent in each direction. - */ - private Bounds expandPointRange(Range range) { - if (range == null) { - return null; - } - else if (range.getLowerBound() == range.getUpperBound()) { - Range expandedRange = ChartHelper.expandRange(range, 5d); - return new DoubleBounds( - expandedRange.getLowerBound(), expandedRange.getUpperBound()); - } - - return new DoubleBounds(range.getLowerBound(), range.getUpperBound()); - } - - - /** - * Creates a new instance of EnhancedLineAndShapeRenderer. - * - * @param plot The plot which is set for the new renderer. - * @param idx This value is not used in the current implementation. - * - * @return a new instance of EnhancedLineAndShapeRenderer. - */ - protected XYLineAndShapeRenderer createRenderer(XYPlot plot, int idx) { - log.debug("Create EnhancedLineAndShapeRenderer for idx: " + idx); - - EnhancedLineAndShapeRenderer r = - new EnhancedLineAndShapeRenderer(true, false); - - r.setPlot(plot); - - return r; - } - - /** * Creates a new instance of <i>IdentifiableNumberAxis</i>. * @@ -1490,17 +270,17 @@ * * @return an instance of IdentifiableNumberAxis. */ - protected NumberAxis createNumberAxis(int idx, String label) { + protected final NumberAxis createNumberAxis(int idx, String label) { YAxisWalker walker = getYAxisWalker(); return new IdentifiableNumberAxis(walker.getId(idx), label); } - /** * Create Y (range) axis for given index. * Shall be overriden by subclasses. */ + @Override protected NumberAxis createYAxis(int index) { YAxisWalker walker = getYAxisWalker(); @@ -1523,113 +303,5 @@ return axis; } - - - /** - * Creates a new LegendItem with <i>name</i> and font provided by - * <i>createLegendLabelFont()</i>. - * - * @param theme The theme of the chart line. - * @param name The displayed name of the item. - * - * @return a new LegendItem instance. - */ - public LegendItem createLegendItem(ThemeDocument theme, String name) { - // OPTIMIZE Pass font, parsed Theme items. - - Color color = theme.parseLineColorField(); - if (color == null) { - color = Color.BLACK; - } - - LegendItem legendItem = new LegendItem(name, color); - - legendItem.setLabelFont(createLegendLabelFont()); - return legendItem; - } - - - /** - * Creates Font (Family and size) to use when creating Legend Items. The - * font size depends in the return value of <i>getLegendFontSize()</i>. - * - * @return a new Font instance with <i>DEFAULT_FONT_NAME</i>. - */ - protected Font createLegendLabelFont() { - return new Font( - DEFAULT_FONT_NAME, - Font.PLAIN, - getLegendFontSize() - ); - } - - - /** - * Create new legend entries, dependent on settings. - * @param plot The plot for which to modify the legend. - */ - public void aggregateLegendEntries(XYPlot plot) { - int AGGR_THRESHOLD = 0; - - if (getChartSettings() == null) { - return; - } - Integer threshold = getChartSettings().getLegendSection() - .getAggregationThreshold(); - - AGGR_THRESHOLD = (threshold != null) ? threshold.intValue() : 0; - - LegendProcessor.aggregateLegendEntries(plot, AGGR_THRESHOLD); - } - - - /** - * Returns a transparently textured paint. - * - * @return a transparently textured paint. - */ - protected static Paint createTransparentPaint() { - // TODO why not use a transparent color? - BufferedImage texture = new BufferedImage( - 1, 1, BufferedImage.TYPE_4BYTE_ABGR); - - return new TexturePaint( - texture, new Rectangle2D.Double(0d, 0d, 0d, 0d)); - } - - - protected void preparePDFContext(CallContext context) { - int[] dimension = getExportDimension(); - - context.putContextValue("chart.width", dimension[0]); - context.putContextValue("chart.height", dimension[1]); - context.putContextValue("chart.marginLeft", 5f); - context.putContextValue("chart.marginRight", 5f); - context.putContextValue("chart.marginTop", 5f); - context.putContextValue("chart.marginBottom", 5f); - context.putContextValue( - "chart.page.format", - ChartExportHelper.DEFAULT_PAGE_SIZE); - } - - - protected void prepareSVGContext(CallContext context) { - int[] dimension = getExportDimension(); - - context.putContextValue("chart.width", dimension[0]); - context.putContextValue("chart.height", dimension[1]); - context.putContextValue( - "chart.encoding", - ChartExportHelper.DEFAULT_ENCODING); - } - - /** - * Retuns the call context. May be null if init hasn't been called yet. - * - * @return the CallContext instance - */ - public CallContext getCallContext() { - return context; - } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator2.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator2.java Tue Jun 05 19:21:16 2018 +0200 @@ -8,302 +8,69 @@ package org.dive4elements.river.exports; -import java.awt.BasicStroke; -import java.awt.Color; +import static org.dive4elements.river.exports.injector.InjectorConstants.CURRENT_KM; + import java.awt.Font; import java.awt.Graphics2D; -import java.awt.Paint; -import java.awt.Stroke; -import java.awt.TexturePaint; import java.awt.Transparency; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; import java.text.NumberFormat; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; -import javax.xml.xpath.XPathConstants; - -import org.apache.log4j.Logger; -import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; -import org.dive4elements.artifactdatabase.state.Settings; -import org.dive4elements.artifacts.Artifact; -import org.dive4elements.artifacts.ArtifactNamespaceContext; import org.dive4elements.artifacts.CallContext; -import org.dive4elements.artifacts.CallMeta; -import org.dive4elements.artifacts.PreferredLocale; import org.dive4elements.artifacts.common.utils.XMLUtils; -import org.dive4elements.river.artifacts.D4EArtifact; -import org.dive4elements.river.artifacts.access.RangeAccess; -import org.dive4elements.river.artifacts.resources.Resources; -import org.dive4elements.river.collections.D4EArtifactCollection; import org.dive4elements.river.java2d.NOPGraphics2D; -import org.dive4elements.river.jfree.AxisDataset; -import org.dive4elements.river.jfree.Bounds; -import org.dive4elements.river.jfree.DoubleBounds; -import org.dive4elements.river.jfree.EnhancedLineAndShapeRenderer; import org.dive4elements.river.jfree.RiverAnnotation; -import org.dive4elements.river.jfree.StableXYDifferenceRenderer; -import org.dive4elements.river.jfree.Style; -import org.dive4elements.river.jfree.StyledAreaSeriesCollection; -import org.dive4elements.river.jfree.StyledSeries; -import org.dive4elements.river.model.River; -import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.Formatter; -import org.dive4elements.river.utils.RiverUtils; import org.jfree.chart.ChartRenderingInfo; import org.jfree.chart.JFreeChart; -import org.jfree.chart.LegendItem; -import org.jfree.chart.LegendItemCollection; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; -import org.jfree.chart.title.TextTitle; import org.jfree.data.Range; -import org.jfree.data.general.Series; -import org.jfree.data.xy.XYDataset; -import org.jfree.ui.RectangleInsets; import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import static org.dive4elements.river.exports.injector.InjectorConstants.CURRENT_KM; /** * Implementation of the OutGenerator interface for charts. * It should provide some basic things that equal in all chart types. * */ -// FIXME: copy/paste of ChartGenerator with LOTS of duplicate code... move duplicates to AbstractChartGenrator! public abstract class ChartGenerator2 extends AbstractChartGenerator { - private static Logger log = Logger.getLogger(ChartGenerator2.class); - - public static final boolean USE_NOP_GRAPHICS = - Boolean.getBoolean("info.rendering.nop.graphics"); - - - public static final int DEFAULT_CHART_WIDTH = 600; - public static final int DEFAULT_CHART_HEIGHT = 400; - public static final String DEFAULT_CHART_FORMAT = "png"; - public static final Color DEFAULT_GRID_COLOR = Color.GRAY; - public static final float DEFAULT_GRID_LINE_WIDTH = 0.3f; - public static final int DEFAULT_FONT_SIZE = 12; - public static final String DEFAULT_FONT_NAME = "Tahoma"; - - - public static final String XPATH_CHART_SIZE = - "/art:action/art:attributes/art:size"; - - public static final String XPATH_CHART_FORMAT = - "/art:action/art:attributes/art:format/@art:value"; - - public static final String XPATH_CHART_X_RANGE = - "/art:action/art:attributes/art:xrange"; - - public static final String XPATH_CHART_Y_RANGE = - "/art:action/art:attributes/art:yrange"; - - /** The document of the incoming out() request.*/ - protected Document request; - - /** The output stream where the data should be written to.*/ - protected OutputStream out; - - /** The CallContext object.*/ - protected CallContext context; - - protected D4EArtifactCollection collection; - - /** Artifact that is used to decorate the chart with meta information.*/ - protected Artifact master; - - /** The settings that should be used during output creation.*/ - protected Settings settings; - - /** Map of datasets ("index"). */ - protected SortedMap<Integer, AxisDataset> datasets; + private static final boolean USE_NOP_GRAPHICS = Boolean.getBoolean("info.rendering.nop.graphics"); /** Map of annotations to add at specific Y-axis. */ - protected SortedMap<Integer, RiverAnnotation> yAnnotations; - - /** List of annotations to insert in plot. */ - protected List<RiverAnnotation> annotations = - new ArrayList<RiverAnnotation>(); - - protected abstract List<AxisSection> buildYAxisSections(); - - protected String outName; + protected SortedMap<Integer, RiverAnnotation> yAnnotations = new TreeMap<>(); private Map<String, IdentifiableNumberAxis> axisNameToAxis = new HashMap<>(); - /** - * Default constructor that initializes internal data structures. - */ - public ChartGenerator2() { - datasets = new TreeMap<>(); - yAnnotations = new TreeMap<>(); - } - - @Override - protected final D4EArtifact getArtifact() { - // FIXME: should already made sure when this member is set - return (D4EArtifact) this.master; - } - - @Override - protected final CallContext getContext() { - return this.context; - } - - @Override - protected final Document getRequest() { - return this.request; - } - - /** - * Adds annotations to list. The given annotation will be visible. - */ - public void addAnnotations(RiverAnnotation annotation) { - annotations.add(annotation); - } - public void addYAnnotation(RiverAnnotation annotation, int axisIndex) { yAnnotations.put(axisIndex, annotation); } - /** - * This method needs to be implemented by concrete subclasses to create new - * instances of JFreeChart. - * - * @return a new instance of a JFreeChart. - */ - public abstract JFreeChart generateChart(); - - - /** For every outable (i.e. facets), this function is - * called and handles the data accordingly. */ @Override - public abstract void doOut( - ArtifactAndFacet bundle, - ThemeDocument attr, - boolean visible); - - - - protected abstract Series getSeriesOf(XYDataset dataset, int idx); - - /** - * Returns the default title of a chart. - * - * @return the default title of a chart. - */ - protected abstract String getDefaultChartTitle(); - - protected abstract String getDefaultYAxisLabel(String axisName); - - - /** - * Returns the default X-Axis label of a chart. - * - * @return the default X-Axis label of a chart. - */ - protected abstract String getDefaultXAxisLabel(); - - /** - * This method is used to create new AxisDataset instances which may differ - * in concrete subclasses. - * - * @param idx The index of an axis. - */ - protected abstract AxisDataset createAxisDataset(int idx); - - - /** - * Combines the ranges of the X axis at index <i>idx</i>. - * - * @param bounds A new Bounds. - * @param idx The index of the X axis that should be comined with - * <i>range</i>. - */ - protected abstract void combineXBounds(Bounds bounds, int idx); - - - /** - * Combines the ranges of the Y axis at index <i>idx</i>. - * - * @param bounds A new Bounds. - * @param index The index of the Y axis that should be comined with. - * <i>range</i>. - */ - protected abstract void combineYBounds(Bounds bounds, int index); - - - /** - * This method is used to determine the ranges for axes at a given index. - * - * @param index The index of the axes at the plot. - * - * @return a Range[] with [xrange, yrange]; - */ - public abstract Range[] getRangesForAxis(int index); - - public abstract Bounds getXBounds(int axis); - - protected abstract void setXBounds(int axis, Bounds bounds); - - public abstract Bounds getYBounds(int axis); - - protected abstract void setYBounds(int axis, Bounds bounds); - - - /** - * This method retrieves the chart subtitle by calling getChartSubtitle() - * and adds it as TextTitle to the chart. - * The default implementation of getChartSubtitle() returns the same - * as getDefaultChartSubtitle() which must be implemented by derived - * classes. If you want to add multiple subtitles to the chart override - * this method and add your subtitles manually. - * - * @param chart The JFreeChart chart object. - */ - protected void addSubtitles(JFreeChart chart) { - String subtitle = getChartSubtitle(); - - if (subtitle != null && subtitle.length() > 0) { - chart.addSubtitle(new TextTitle(subtitle)); - } - } - - /** - * Generate chart. - */ - @Override - public void generate() throws IOException { - + protected void doGenerate(final CallContext context, final OutputStream out, final String outName) throws IOException { log.debug("ChartGenerator2.generate"); - if (outName.indexOf("chartinfo") > 0) { - generateInfo(); - } - else { - generateImage(); - } + if (outName.indexOf("chartinfo") > 0) + generateInfo(context, out); + else + generateImage(context); } - - /** Generate only meta infos */ - private void generateInfo() throws IOException { + /** + * Generate only meta infos + */ + private void generateInfo(final CallContext context, final OutputStream out) { log.debug("ChartInfoGenerator2.generateInfo"); - JFreeChart chart = generateChart(); + JFreeChart chart = generateChart(context); int[] size = getSize(); if (size == null) { @@ -348,142 +115,16 @@ XMLUtils.toStream(doc, out); } - /** Generate the diagram as an image. */ - private void generateImage() throws IOException { - log.debug("ChartGenerator2.generateImage"); - - JFreeChart chart = generateChart(); - - String format = getFormat(); - int[] size = getSize(); - - if (size == null) { - size = getExportDimension(); - } - - context.putContextValue("chart.width", size[0]); - context.putContextValue("chart.height", size[1]); - - if (format.equals(ChartExportHelper.FORMAT_PNG)) { - context.putContextValue("chart.image.format", "png"); - - ChartExportHelper.exportImage( - out, - chart, - context); - } - else if (format.equals(ChartExportHelper.FORMAT_PDF)) { - preparePDFContext(context); - - ChartExportHelper.exportPDF( - out, - chart, - context); - } - else if (format.equals(ChartExportHelper.FORMAT_SVG)) { - prepareSVGContext(context); - - ChartExportHelper.exportSVG( - out, - chart, - context); - } - else if (format.equals(ChartExportHelper.FORMAT_CSV)) { - context.putContextValue("chart.image.format", "csv"); - - ChartExportHelper.exportCSV( - out, - chart, - context); - } - } - - - @Override - public void init( - String outName, - Document request, - OutputStream out, - CallContext context - ) { - log.debug("ChartGenerator2.init"); - - this.outName = outName; - this.request = request; - this.out = out; - this.context = context; - } - - - /** Sets the master artifact. */ - @Override - public void setMasterArtifact(Artifact master) { - this.master = master; - } - - - /** - * Gets the master artifact. - * @return the master artifact. - */ - public Artifact getMaster() { - return master; - } - - - /** Sets the collection. */ - @Override - public void setCollection(D4EArtifactCollection collection) { - this.collection = collection; - } - - - @Override - public void setSettings(Settings settings) { - this.settings = settings; - } - - - /** - * Return instance of <i>ChartSettings</i> with a chart specific section - * but with no axes settings. - * - * @return an instance of <i>ChartSettings</i>. - */ - @Override - public Settings getSettings() { - if (this.settings != null) { - return this.settings; - } - - ChartSettings settings = new ChartSettings(); - - ChartSection chartSection = buildChartSection(); - LegendSection legendSection = buildLegendSection(); - ExportSection exportSection = buildExportSection(); - - settings.setChartSection(chartSection); - settings.setLegendSection(legendSection); - settings.setExportSection(exportSection); - - List<AxisSection> axisSections = buildAxisSections(); - for (AxisSection axisSection: axisSections) { - settings.addAxisSection(axisSection); - } - - return settings; - } - - /** * Creates a new <i>ChartSection</i>. * * @return a new <i>ChartSection</i>. */ - protected ChartSection buildChartSection() { + @Override + protected ChartSection buildChartSection(final CallContext context) { ChartSection chartSection = new ChartSection(); - chartSection.setTitle(getChartTitle()); - chartSection.setSubtitle(getChartSubtitlePure()); + chartSection.setTitle(getChartTitle(context)); + chartSection.setSubtitle(getChartSubtitlePure(context)); chartSection.setDisplayGrid(isGridVisible()); chartSection.setDisplayLogo(showLogo()); chartSection.setLogoVPlacement(logoVPlace()); @@ -491,198 +132,7 @@ return chartSection; } - - /** - * Creates a new <i>LegendSection</i>. - * - * @return a new <i>LegendSection</i>. - */ - protected LegendSection buildLegendSection() { - LegendSection legendSection = new LegendSection(); - legendSection.setVisibility(isLegendVisible()); - legendSection.setFontSize(getLegendFontSize()); - legendSection.setAggregationThreshold(10); - return legendSection; - } - - - /** - * Creates a new <i>ExportSection</i> with default values <b>WIDTH=600</b> - * and <b>HEIGHT=400</b>. - * - * @return a new <i>ExportSection</i>. - */ - protected ExportSection buildExportSection() { - ExportSection exportSection = new ExportSection(); - exportSection.setWidth(600); - exportSection.setHeight(400); - return exportSection; - } - - - /** - * Creates a list of Sections that contains all axes of the chart (including - * X and Y axes). - * - * @return a list of Sections for each axis in this chart. - */ - protected List<AxisSection> buildAxisSections() { - List<AxisSection> axisSections = new ArrayList<AxisSection>(); - - axisSections.addAll(buildXAxisSections()); - axisSections.addAll(buildYAxisSections()); - - return axisSections; - } - - - /** - * Creates a new Section for chart's X axis. - * - * @return a List that contains a Section for the X axis. - */ - protected List<AxisSection> buildXAxisSections() { - List<AxisSection> axisSections = new ArrayList<AxisSection>(); - - String identifier = "X"; - - AxisSection axisSection = new AxisSection(); - axisSection.setIdentifier(identifier); - axisSection.setLabel(getXAxisLabel()); - axisSection.setFontSize(14); - axisSection.setFixed(false); - - // XXX We are able to find better default ranges that [0,0], but the Y - // axes currently have no better ranges set. - axisSection.setUpperRange(0d); - axisSection.setLowerRange(0d); - - axisSections.add(axisSection); - - return axisSections; - } - - - /** - * Returns the <i>settings</i> as <i>ChartSettings</i>. - * - * @return the <i>settings</i> as <i>ChartSettings</i> or null, if - * <i>settings</i> is not an instance of <i>ChartSettings</i>. - */ - public ChartSettings getChartSettings() { - if (settings instanceof ChartSettings) { - return (ChartSettings) settings; - } - - return null; - } - - - /** - * Returns the chart title provided by <i>settings</i>. - * - * @param settings A ChartSettings object. - * - * @return the title provided by <i>settings</i> or null if no - * <i>ChartSection</i> is provided by <i>settings</i>. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public String getChartTitle(ChartSettings settings) { - ChartSection cs = settings.getChartSection(); - return cs != null ? cs.getTitle() : null; - } - - - /** - * Returns the chart subtitle provided by <i>settings</i>. - * - * @param settings A ChartSettings object. - * - * @return the subtitle provided by <i>settings</i> or null if no - * <i>ChartSection</i> is provided by <i>settings</i>. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public String getChartSubtitle(ChartSettings settings) { - ChartSection cs = settings.getChartSection(); - return cs != null ? cs.getSubtitle() : null; - } - - - /** - * Returns a boolean object that determines if the chart grid should be - * visible or not. This information needs to be provided by <i>settings</i>, - * otherweise the default is true. - * - * @param settings A ChartSettings object. - * - * @return true, if the chart grid should be visible otherwise false. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public boolean isGridVisible(ChartSettings settings) { - ChartSection cs = settings.getChartSection(); - Boolean displayGrid = cs.getDisplayGrid(); - - return displayGrid != null ? displayGrid : true; - } - - - /** - * Returns a boolean object that determines if the chart legend should be - * visible or not. This information needs to be provided by <i>settings</i>, - * otherwise the default is true. - * - * @param settings A ChartSettings object. - * - * @return true, if the chart legend should be visible otherwise false. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public boolean isLegendVisible(ChartSettings settings) { - LegendSection ls = settings.getLegendSection(); - Boolean displayLegend = ls.getVisibility(); - - return displayLegend != null ? displayLegend : true; - } - - - /** - * Returns the legend font size specified in <i>settings</i> or null if no - * <i>LegendSection</i> is provided by <i>settings</i>. - * - * @param settings A ChartSettings object. - * - * @return the legend font size or null. - * - * @throws NullPointerException if <i>settings</i> is null. - */ - public Integer getLegendFontSize(ChartSettings settings) { - LegendSection ls = settings.getLegendSection(); - return ls != null ? ls.getFontSize() : null; - } - - - /** - * Returns the title of a chart. The return value depends on the existence - * of ChartSettings: if there are ChartSettings set, this method returns the - * chart title provided by those settings. Otherwise, this method returns - * getDefaultChartTitle(). - * - * @return the title of a chart. - */ - protected String getChartTitle() { - ChartSettings chartSettings = getChartSettings(); - - if (chartSettings != null) { - return getChartTitle(chartSettings); - } - - return getDefaultChartTitle(); - } - - protected String interpolateVariables(String s) { + protected String interpolateVariables(final CallContext context, String s) { log.debug("Interpolate variables in string '" + s + "'"); Object radius = context.getContextValue("radius"); if (radius instanceof Double) { @@ -707,17 +157,18 @@ * existence of ChartSettings: if there are ChartSettings set, this method * returns the chart title provided by those settings. Otherwise, this * method returns getDefaultChartSubtitle(). + * @param context * * @return the subtitle of a chart. */ - protected String getChartSubtitlePure() { + protected String getChartSubtitlePure(CallContext context) { ChartSettings chartSettings = getChartSettings(); String subTitle = chartSettings != null ? getChartSubtitle(chartSettings) - : getDefaultChartSubtitle(); + : getDefaultChartSubtitle(context); - String defSubTitle = getDefaultChartSubtitle(); + String defSubTitle = getDefaultChartSubtitle(context); if (subTitle == null) { subTitle = defSubTitle != null ? defSubTitle : ""; @@ -726,162 +177,9 @@ return subTitle; } - protected String getChartSubtitle() { - return interpolateVariables(getChartSubtitlePure()); - } - - - /** - * This method always returns null. Override it in subclasses that require - * subtitles. - * - * @return null. - */ - protected String getDefaultChartSubtitle() { - // Override this method in subclasses - return null; - } - - - /** - * This method is used to determine, if the chart's legend is visible or - * not. If a <i>settings</i> instance is set, this instance determines the - * visibility otherwise, this method returns true as default if no - * <i>settings</i> is set. - * - * @return true, if the legend should be visible, otherwise false. - */ - protected boolean isLegendVisible() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings != null) { - return isLegendVisible(chartSettings); - } - - return true; - } - - - /** Where to place the logo. */ - protected String logoHPlace() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings != null) { - ChartSection cs = chartSettings.getChartSection(); - String place = cs.getLogoHPlacement(); - - return place; - } - return "center"; - } - - - /** Where to place the logo. */ - protected String logoVPlace() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings != null) { - ChartSection cs = chartSettings.getChartSection(); - String place = cs.getLogoVPlacement(); - - return place; - } - return "top"; - } - - - /** Return the logo id from settings. */ - protected String showLogo(ChartSettings chartSettings) { - if (chartSettings != null) { - ChartSection cs = chartSettings.getChartSection(); - String logo = cs.getDisplayLogo(); - - return logo; - } - return "none"; - } - - - /** - * This method is used to determine if a logo should be added to the plot. - * - * @return logo name (null if none). - */ - protected String showLogo() { - ChartSettings chartSettings = getChartSettings(); - return showLogo(chartSettings); - } - - - /** - * This method is used to determine the font size of the chart's legend. If - * a <i>settings</i> instance is set, this instance determines the font - * size, otherwise this method returns 12 as default if no <i>settings</i> - * is set or if it doesn't provide a legend font size. - * - * @return a legend font size. - */ - protected int getLegendFontSize() { - Integer fontSize = null; - - ChartSettings chartSettings = getChartSettings(); - if (chartSettings != null) { - fontSize = getLegendFontSize(chartSettings); - } - - return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; - } - - - /** - * This method is used to determine if the resulting chart should display - * grid lines or not. <b>Note: this method always returns true!</b> - * - * @return true, if the chart should display grid lines, otherwise false. - */ - protected boolean isGridVisible() { - return true; - } - - - /** - * Returns the X-Axis label of a chart. - * - * @return the X-Axis label of a chart. - */ - protected String getXAxisLabel() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings == null) { - return getDefaultXAxisLabel(); - } - - AxisSection as = chartSettings.getAxisSection("X"); - if (as != null) { - String label = as.getLabel(); - - if (label != null) { - return label; - } - } - - return getDefaultXAxisLabel(); - } - - - /** - * This method returns the font size for the X axis. If the font size is - * specified in ChartSettings (if <i>chartSettings</i> is set), this size is - * returned. Otherwise the default font size 12 is returned. - * - * @return the font size for the x axis. - */ - protected int getXAxisLabelFontSize() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings == null) { - return DEFAULT_FONT_SIZE; - } - - AxisSection as = chartSettings.getAxisSection("X"); - Integer fontSize = as.getFontSize(); - - return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; + @Override + protected String getChartSubtitle(CallContext context) { + return interpolateVariables(context, getChartSubtitlePure(context)); } /** @@ -911,29 +209,6 @@ return fontSize != null ? fontSize : DEFAULT_FONT_SIZE; } - /** - * This method returns the export dimension specified in ChartSettings as - * int array [width,height]. - * - * @return an int array with [width,height]. - */ - protected int[] getExportDimension() { - ChartSettings chartSettings = getChartSettings(); - if (chartSettings == null) { - return new int[] { 600, 400 }; - } - - ExportSection export = chartSettings.getExportSection(); - Integer width = export.getWidth(); - Integer height = export.getHeight(); - - if (width != null && height != null) { - return new int[] { width, height }; - } - - return new int[] { 600, 400 }; - } - protected abstract String getYAxisLabel(String axisName); /** @@ -959,9 +234,7 @@ return null; } - Boolean fixed = as.isFixed(); - - if (fixed != null && fixed) { + if (as.isFixed()) { Double upper = as.getUpperRange(); Double lower = as.getLowerRange(); @@ -975,486 +248,6 @@ return null; } - - /** - * Adds a new AxisDataset which contains <i>dataset</i> at index <i>idx</i>. - * - * @param dataset An XYDataset. - * @param idx The axis index. - * @param visible Determines, if the dataset should be visible or not. - */ - public void addAxisDataset(XYDataset dataset, int idx, boolean visible) { - if (dataset == null || idx < 0) { - return; - } - - AxisDataset axisDataset = getAxisDataset(idx); - - Bounds[] xyBounds = ChartHelper.getBounds(dataset); - - if (xyBounds == null) { - log.warn("Skip XYDataset for Axis (invalid ranges): " + idx); - return; - } - - if (visible) { - if (log.isDebugEnabled()) { - log.debug("Add new AxisDataset at index: " + idx); - log.debug("X extent: " + xyBounds[0]); - log.debug("Y extent: " + xyBounds[1]); - } - - axisDataset.addDataset(dataset); - } - - combineXBounds(xyBounds[0], 0); - combineYBounds(xyBounds[1], idx); - } - - - /** - * This method grants access to the AxisDatasets stored in <i>datasets</i>. - * If no AxisDataset exists for index <i>idx</i>, a new AxisDataset is - * created using <i>createAxisDataset()</i>. - * - * @param idx The index of the desired AxisDataset. - * - * @return an existing or new AxisDataset. - */ - public AxisDataset getAxisDataset(int idx) { - AxisDataset axisDataset = datasets.get(idx); - - if (axisDataset == null) { - axisDataset = createAxisDataset(idx); - datasets.put(idx, axisDataset); - } - - return axisDataset; - } - - - /** - * Adjust some Stroke/Grid parameters for <i>plot</i>. The chart - * <i>Settings</i> are applied in this method. - * - * @param plot The XYPlot which is adapted. - */ - protected void adjustPlot(XYPlot plot) { - Stroke gridStroke = new BasicStroke( - DEFAULT_GRID_LINE_WIDTH, - BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER, - 3.0f, - new float[] { 3.0f }, - 0.0f); - - ChartSettings cs = getChartSettings(); - boolean isGridVisible = cs != null ? isGridVisible(cs) : true; - - plot.setDomainGridlineStroke(gridStroke); - plot.setDomainGridlinePaint(DEFAULT_GRID_COLOR); - plot.setDomainGridlinesVisible(isGridVisible); - - plot.setRangeGridlineStroke(gridStroke); - plot.setRangeGridlinePaint(DEFAULT_GRID_COLOR); - plot.setRangeGridlinesVisible(isGridVisible); - - plot.setAxisOffset(new RectangleInsets(0d, 0d, 0d, 0d)); - } - - - /** - * This helper mehtod is used to extract the current locale from instance - * vairable <i>context</i>. - * - * @return the current locale. - */ - protected Locale getLocale() { - CallMeta meta = context.getMeta(); - PreferredLocale[] prefs = meta.getLanguages(); - - int len = prefs != null ? prefs.length : 0; - - Locale[] locales = new Locale[len]; - - for (int i = 0; i < len; i++) { - locales[i] = prefs[i].getLocale(); - } - - return meta.getPreferredLocale(locales); - } - - - /** - * Look up \param key in i18n dictionary. - * @param key key for which to find i18nd version. - * @param def default, returned if lookup failed. - * @return value found in i18n dictionary, \param def if no value found. - */ - public String msg(String key, String def) { - return Resources.getMsg(context.getMeta(), key, def); - } - - /** - * Look up \param key in i18n dictionary. - * @param key key for which to find i18nd version. - * @return value found in i18n dictionary, key itself if failed. - */ - public String msg(String key) { - return Resources.getMsg(context.getMeta(), key, key); - } - - public String msg(String key, String def, Object[] args) { - return Resources.getMsg(context.getMeta(), key, def, args); - } - - /** - * Returns the size of a chart export as array which has been specified by - * the incoming request document. - * - * @return the size of a chart as [width, height] or null if no width or - * height are given in the request document. - */ - protected int[] getSize() { - int[] size = new int[2]; - - Element sizeEl = (Element)XMLUtils.xpath( - request, - XPATH_CHART_SIZE, - XPathConstants.NODE, - ArtifactNamespaceContext.INSTANCE); - - if (sizeEl != null) { - String uri = ArtifactNamespaceContext.NAMESPACE_URI; - - String w = sizeEl.getAttributeNS(uri, "width"); - String h = sizeEl.getAttributeNS(uri, "height"); - - if (w.length() > 0 && h.length() > 0) { - try { - size[0] = Integer.parseInt(w); - size[1] = Integer.parseInt(h); - } - catch (NumberFormatException nfe) { - log.warn("Wrong values for chart width/height."); - } - } - } - - return size[0] > 0 && size[1] > 0 ? size : null; - } - - - /** - * This method returns the format specified in the <i>request</i> document - * or <i>DEFAULT_CHART_FORMAT</i> if no format is specified in - * <i>request</i>. - * - * @return the format used to export this chart. - */ - protected String getFormat() { - String format = (String) XMLUtils.xpath( - request, - XPATH_CHART_FORMAT, - XPathConstants.STRING, - ArtifactNamespaceContext.INSTANCE); - - return format == null || format.length() == 0 - ? DEFAULT_CHART_FORMAT - : format; - } - - /** - * Returns the X-Axis range as String array from request document. - * If the (x|y)range elements are not found in request document, return - * null (i.e. not zoomed). - * - * @return a String array with [lower, upper], null if not in document. - */ - protected String[] getDomainAxisRangeFromRequest() { - Element xrange = (Element)XMLUtils.xpath( - request, - XPATH_CHART_X_RANGE, - XPathConstants.NODE, - ArtifactNamespaceContext.INSTANCE); - - if (xrange == null) { - return null; - } - - String uri = ArtifactNamespaceContext.NAMESPACE_URI; - - String lower = xrange.getAttributeNS(uri, "from"); - String upper = xrange.getAttributeNS(uri, "to"); - - return new String[] { lower, upper }; - } - - - /** Returns null if the (x|y)range-element was not found in - *request document. - * This usally means that the axis are not manually zoomed, i.e. showing - * full data extent. */ - protected String[] getValueAxisRangeFromRequest() { - Element yrange = (Element)XMLUtils.xpath( - request, - XPATH_CHART_Y_RANGE, - XPathConstants.NODE, - ArtifactNamespaceContext.INSTANCE); - - if (yrange == null) { - return null; - } - - - String uri = ArtifactNamespaceContext.NAMESPACE_URI; - - String lower = yrange.getAttributeNS(uri, "from"); - String upper = yrange.getAttributeNS(uri, "to"); - - return new String[] { lower, upper }; - } - - - /** - * Returns the default size of a chart export as array. - * - * @return the default size of a chart as [width, height]. - */ - protected int[] getDefaultSize() { - return new int[] { DEFAULT_CHART_WIDTH, DEFAULT_CHART_HEIGHT }; - } - - - /** - * Add datasets stored in instance variable <i>datasets</i> to plot. - * <i>datasets</i> actually stores instances of AxisDataset, so each of this - * datasets is mapped to a specific axis as well. - * - * @param plot plot to add datasets to. - */ - protected void addDatasets(XYPlot plot) { - log.debug("addDatasets()"); - - // AxisDatasets are sorted, but some might be empty. - // Thus, generate numbering on the fly. - int axisIndex = 0; - int datasetIndex = 0; - - for (Map.Entry<Integer, AxisDataset> entry: datasets.entrySet()) { - if (!entry.getValue().isEmpty()) { - // Add axis and range information. - AxisDataset axisDataset = entry.getValue(); - NumberAxis axis = createYAxis(entry.getKey()); - - plot.setRangeAxis(axisIndex, axis); - - if (axis.getAutoRangeIncludesZero()) { - axisDataset.setRange( - Range.expandToInclude(axisDataset.getRange(), 0d)); - } - - setYBounds(axisIndex, expandPointRange(axisDataset.getRange())); - - // Add contained datasets, mapping to axis. - for (XYDataset dataset: axisDataset.getDatasets()) { - try { - plot.setDataset(datasetIndex, dataset); - plot.mapDatasetToRangeAxis(datasetIndex, axisIndex); - - applyThemes(plot, dataset, - datasetIndex, - axisDataset.isArea(dataset)); - - datasetIndex++; - } - catch (RuntimeException re) { - log.error(re); - } - } - - axisDataset.setPlotAxisIndex(axisIndex); - axisIndex++; - } - } - } - - - /** - * @param idx "index" of dataset/series (first dataset to be drawn has - * index 0), correlates with renderer index. - * @param isArea true if the series describes an area and shall be rendered - * as such. - */ - protected void applyThemes( - XYPlot plot, - XYDataset series, - int idx, - boolean isArea - ) { - if (isArea) { - applyAreaTheme(plot, (StyledAreaSeriesCollection) series, idx); - } - else { - applyLineTheme(plot, series, idx); - } - } - - - /** - * This method applies the themes defined in the series itself. Therefore, - * <i>StyledXYSeries.applyTheme()</i> is called, which modifies the renderer - * for the series. - * - * @param plot The plot. - * @param dataset The XYDataset which needs to support Series objects. - * @param idx The index of the renderer / dataset. - */ - protected void applyLineTheme(XYPlot plot, XYDataset dataset, int idx) { - log.debug("Apply LineTheme for dataset at index: " + idx); - - LegendItemCollection lic = new LegendItemCollection(); - LegendItemCollection anno = plot.getFixedLegendItems(); - - Font legendFont = createLegendLabelFont(); - - XYLineAndShapeRenderer renderer = createRenderer(plot, idx); - - for (int s = 0, num = dataset.getSeriesCount(); s < num; s++) { - Series series = getSeriesOf(dataset, s); - - if (series instanceof StyledSeries) { - Style style = ((StyledSeries) series).getStyle(); - style.applyTheme(renderer, s); - } - - // special case: if there is just one single item, we need to enable - // points for this series, otherwise we would not see anything in - // the chart area. - if (series.getItemCount() == 1) { - renderer.setSeriesShapesVisible(s, true); - } - - LegendItem legendItem = renderer.getLegendItem(idx, s); - if (legendItem.getLabel().endsWith(" ") || - legendItem.getLabel().endsWith("interpol")) { - legendItem = null; - } - - if (legendItem != null) { - legendItem.setLabelFont(legendFont); - lic.add(legendItem); - } - else { - log.warn("Could not get LegentItem for renderer: " - + idx + ", series-idx " + s); - } - } - - if (anno != null) { - lic.addAll(anno); - } - - plot.setFixedLegendItems(lic); - - plot.setRenderer(idx, renderer); - } - - - /** - * @param plot The plot. - * @param area A StyledAreaSeriesCollection object. - * @param idx The index of the dataset. - */ - protected void applyAreaTheme( - XYPlot plot, - StyledAreaSeriesCollection area, - int idx - ) { - LegendItemCollection lic = new LegendItemCollection(); - LegendItemCollection anno = plot.getFixedLegendItems(); - - Font legendFont = createLegendLabelFont(); - - log.debug("Registering an 'area'renderer at idx: " + idx); - - StableXYDifferenceRenderer dRenderer = - new StableXYDifferenceRenderer(); - - if (area.getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) { - dRenderer.setPositivePaint(createTransparentPaint()); - } - - plot.setRenderer(idx, dRenderer); - - area.applyTheme(dRenderer); - - // i18n - dRenderer.setAreaLabelNumberFormat( - Formatter.getFormatter(context.getMeta(), 2, 4)); - - dRenderer.setAreaLabelTemplate(Resources.getMsg( - context.getMeta(), "area.label.template", "Area=%sm2")); - - LegendItem legendItem = dRenderer.getLegendItem(idx, 0); - if (legendItem != null) { - legendItem.setLabelFont(legendFont); - lic.add(legendItem); - } - else { - log.warn("Could not get LegentItem for renderer: " - + idx + ", series-idx " + 0); - } - - if (anno != null) { - lic.addAll(anno); - } - - plot.setFixedLegendItems(lic); - } - - - /** - * Expands a given range if it collapses into one point. - * - * @param range Range to be expanded if upper == lower bound. - * - * @return Bounds of point plus 5 percent in each direction. - */ - private Bounds expandPointRange(Range range) { - if (range == null) { - return null; - } - else if (range.getLowerBound() == range.getUpperBound()) { - Range expandedRange = ChartHelper.expandRange(range, 5d); - return new DoubleBounds( - expandedRange.getLowerBound(), expandedRange.getUpperBound()); - } - - return new DoubleBounds(range.getLowerBound(), range.getUpperBound()); - } - - - /** - * Creates a new instance of EnhancedLineAndShapeRenderer. - * - * @param plot The plot which is set for the new renderer. - * @param idx This value is not used in the current implementation. - * - * @return a new instance of EnhancedLineAndShapeRenderer. - */ - protected XYLineAndShapeRenderer createRenderer(XYPlot plot, int idx) { - log.debug("Create EnhancedLineAndShapeRenderer for idx: " + idx); - - EnhancedLineAndShapeRenderer r = - new EnhancedLineAndShapeRenderer(true, false); - - r.setPlot(plot); - - return r; - } - - /** * Creates a new instance of <i>IdentifiableNumberAxis</i>. * @@ -1463,15 +256,15 @@ * * @return an instance of IdentifiableNumberAxis. */ - protected NumberAxis createNumberAxis(int idx, String label) { + protected final NumberAxis createNumberAxis(int idx, String label) { return new IdentifiableNumberAxis(axisIndexToName(idx), label); } - /** * Create Y (range) axis for given index. * Shall be overriden by subclasses. */ + @Override protected NumberAxis createYAxis(int index) { Font labelFont = new Font( @@ -1496,114 +289,6 @@ return axis; } - - /** - * Creates a new LegendItem with <i>name</i> and font provided by - * <i>createLegendLabelFont()</i>. - * - * @param theme The theme of the chart line. - * @param name The displayed name of the item. - * - * @return a new LegendItem instance. - */ - public LegendItem createLegendItem(ThemeDocument theme, String name) { - // OPTIMIZE Pass font, parsed Theme items. - - Color color = theme.parseLineColorField(); - if (color == null) { - color = Color.BLACK; - } - - LegendItem legendItem = new LegendItem(name, color); - - legendItem.setLabelFont(createLegendLabelFont()); - return legendItem; - } - - - /** - * Creates Font (Family and size) to use when creating Legend Items. The - * font size depends in the return value of <i>getLegendFontSize()</i>. - * - * @return a new Font instance with <i>DEFAULT_FONT_NAME</i>. - */ - protected Font createLegendLabelFont() { - return new Font( - DEFAULT_FONT_NAME, - Font.PLAIN, - getLegendFontSize() - ); - } - - - /** - * Create new legend entries, dependent on settings. - * @param plot The plot for which to modify the legend. - */ - public void aggregateLegendEntries(XYPlot plot) { - int AGGR_THRESHOLD = 0; - - if (getChartSettings() == null) { - return; - } - Integer threshold = getChartSettings().getLegendSection() - .getAggregationThreshold(); - - AGGR_THRESHOLD = (threshold != null) ? threshold.intValue() : 0; - - LegendProcessor.aggregateLegendEntries(plot, AGGR_THRESHOLD); - } - - - /** - * Returns a transparently textured paint. - * - * @return a transparently textured paint. - */ - protected static Paint createTransparentPaint() { - // TODO why not use a transparent color? - BufferedImage texture = new BufferedImage( - 1, 1, BufferedImage.TYPE_4BYTE_ABGR); - - return new TexturePaint( - texture, new Rectangle2D.Double(0d, 0d, 0d, 0d)); - } - - - protected void preparePDFContext(CallContext context) { - int[] dimension = getExportDimension(); - - context.putContextValue("chart.width", dimension[0]); - context.putContextValue("chart.height", dimension[1]); - context.putContextValue("chart.marginLeft", 5f); - context.putContextValue("chart.marginRight", 5f); - context.putContextValue("chart.marginTop", 5f); - context.putContextValue("chart.marginBottom", 5f); - context.putContextValue( - "chart.page.format", - ChartExportHelper.DEFAULT_PAGE_SIZE); - } - - - protected void prepareSVGContext(CallContext context) { - int[] dimension = getExportDimension(); - - context.putContextValue("chart.width", dimension[0]); - context.putContextValue("chart.height", dimension[1]); - context.putContextValue( - "chart.encoding", - ChartExportHelper.DEFAULT_ENCODING); - } - - /** - * Retuns the call context. May be null if init hasn't been called yet. - * - * @return the CallContext instance - */ - public CallContext getCallContext() { - return context; - } - public final IdentifiableNumberAxis getAxis(final String axisName) { return axisNameToAxis.get(axisName); } @@ -1612,4 +297,9 @@ public final int getNumYAxes() { return axisNameToAxis.size(); } + + protected final void addYAnnotationsToRenderer(final XYPlot plot) { + final AnnotationRenderer annotationRenderer = new AnnotationRenderer(getChartSettings(), getDatasets(), DEFAULT_FONT_NAME); + annotationRenderer.addYAnnotationsToRenderer(plot, this.yAnnotations); + } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartInfoGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartInfoGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -69,6 +69,7 @@ this.generator = generator; } + @Override public void setup(Object config) { log.debug("ChartInfoGenerator.setup"); } @@ -81,6 +82,7 @@ * @param out * @param context */ + @Override public void init( String outName, Document request, @@ -98,21 +100,21 @@ * * @param master The master artifact */ + @Override public void setMasterArtifact(Artifact master) { generator.setMasterArtifact(master); } - /** * Dispatches the operation to the instantiated generator. * * @param collection The collection. */ + @Override public void setCollection(D4EArtifactCollection collection) { generator.setCollection(collection); } - - + /** * Dispatches the operation to the instantiated generator. */ @@ -137,7 +139,7 @@ { log.debug("ChartInfoGenerator.generate"); - JFreeChart chart = generator.generateChart(); + JFreeChart chart = generator.generateChart(generator.getContext()); int[] size = generator.getSize(); if (size == null) {
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartSection.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartSection.java Tue Jun 05 19:21:16 2018 +0200 @@ -93,8 +93,8 @@ } - public Boolean getDisplayGrid() { - return getBooleanValue(DISPLAYGRID_ATTR); + public boolean getDisplayGrid() { + return getBooleanValue(DISPLAYGRID_ATTR, true); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -16,13 +16,8 @@ import java.util.List; import org.apache.log4j.Logger; -import org.jfree.chart.LegendItemCollection; -import org.jfree.chart.annotations.XYBoxAnnotation; -import org.jfree.chart.annotations.XYTextAnnotation; -import org.jfree.chart.plot.XYPlot; -import org.jfree.data.xy.XYSeries; - import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.DataProvider; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.geom.Lines; @@ -35,8 +30,13 @@ import org.dive4elements.river.model.FastCrossSectionLine; import org.dive4elements.river.themes.TextStyle; import org.dive4elements.river.themes.ThemeDocument; +import org.dive4elements.river.utils.Formatter; import org.dive4elements.river.utils.RiverUtils; -import org.dive4elements.river.utils.Formatter; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.annotations.XYBoxAnnotation; +import org.jfree.chart.annotations.XYTextAnnotation; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.xy.XYSeries; /** @@ -93,7 +93,7 @@ * Get localized chart title. */ @Override - public String getDefaultChartTitle() { + public String getDefaultChartTitle(final CallContext context) { Object[] i18n_msg_args = new Object[] { getRiverName() }; @@ -103,19 +103,19 @@ /** Always return default subtitle. */ @Override - protected String getChartSubtitle() { + protected String getChartSubtitle(CallContext context) { // XXX NOTE: overriding this method disables ChartSettings subtitle! // The default implementation of this method in ChartGenerator returns // the subtitle changed via the chart settings dialog. This method // always returns the subtitle containing river and km, NEVER the // ChartSettings subtitle! - return getDefaultChartSubtitle(); + return getDefaultChartSubtitle(context); } - + /** Get Charts default subtitle. */ @Override - protected String getDefaultChartSubtitle() { + protected String getDefaultChartSubtitle(final CallContext context) { List<DataProvider> providers = context.getDataProvider( CrossSectionFacet.BLACKBOARD_CS_MASTER_DATA); @@ -164,8 +164,7 @@ } @Override - protected void addAnnotationsToRenderer(XYPlot plot) { - super.addAnnotationsToRenderer(plot); + protected void doAddFurtherAnnotations(XYPlot plot, List<RiverAnnotation> annotations) { // Paints for the boxes/lines. Stroke basicStroke = new BasicStroke(1.0f); @@ -179,7 +178,7 @@ plot.getDomainAxis(0), plot.getRangeAxis()); - for(RiverAnnotation fa : this.annotations) { + for(RiverAnnotation fa : annotations) { // Access text styling, if any. ThemeDocument theme = fa.getTheme(); @@ -245,14 +244,14 @@ } @Override - protected String getDefaultXAxisLabel() { + protected String getDefaultXAxisLabel(final CallContext context) { return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); } @Override protected String getDefaultYAxisLabel(int pos) { - D4EArtifact flys = (D4EArtifact) master; + D4EArtifact flys = getArtifact(); String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); @@ -279,6 +278,8 @@ log.error("No facet name for doOut(). No output generated!"); return; } + + CallContext context = getContext(); if (name.equals(CROSS_SECTION)) { doCrossSectionOut( @@ -351,11 +352,13 @@ // DO NOT SORT DATA! This destroys the gaps indicated by NaNs. StyledXYSeries series = new StyledXYSeries(seriesName, false, theme); + CallContext context = getContext(); + if (!theme.parseShowLineLabel()) { series.setLabel(""); } if (theme.parseShowWidth()) { - NumberFormat nf = Formatter.getMeterFormat(this.context); + NumberFormat nf = Formatter.getMeterFormat(context); String labelAdd = "b=" + nf.format(lines.width) + "m"; if (series.getLabel().length() == 0) { series.setLabel(labelAdd); @@ -366,8 +369,8 @@ } if (theme.parseShowLevel() && lines.points.length > 1 && lines.points[1].length > 0) { - NumberFormat nf = Formatter.getMeterFormat(this.context); - D4EArtifact flys = (D4EArtifact) master; + NumberFormat nf = Formatter.getMeterFormat(context); + D4EArtifact flys = getArtifact(); String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); @@ -380,7 +383,7 @@ } } if (theme.parseShowMiddleHeight() && lines.width != 0) { - NumberFormat nf = Formatter.getMeterFormat(this.context); + NumberFormat nf = Formatter.getMeterFormat(context); String labelAdd = "T=" + nf.format(lines.area / lines.width) + "m"; // : " + lines.area + "/" + lines.width); if (series.getLabel().length() == 0) { @@ -450,9 +453,9 @@ * @return a new <i>ChartSection</i>. */ @Override - protected ChartSection buildChartSection() { + protected ChartSection buildChartSection(final CallContext context) { ChartSection chartSection = new ChartSection(); - chartSection.setTitle(getChartTitle()); + chartSection.setTitle(getChartTitle(context)); chartSection.setDisplayGrid(isGridVisible()); chartSection.setDisplayLogo(showLogo()); chartSection.setLogoVPlacement(logoVPlace());
--- a/artifacts/src/main/java/org/dive4elements/river/exports/DiagramGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DiagramGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -10,9 +10,7 @@ import java.awt.Color; import java.awt.Font; - import java.text.NumberFormat; - import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -21,62 +19,43 @@ import java.util.List; import java.util.Map; import java.util.Set; - +import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.regex.Matcher; - -import java.io.OutputStream; import javax.swing.ImageIcon; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; - import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifactdatabase.state.Facet; - import org.dive4elements.artifacts.CallContext; - import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.exports.DiagramAttributes.AxisAttributes; import org.dive4elements.river.exports.process.Processor; - -import org.dive4elements.river.jfree.RiverAnnotation; -import org.dive4elements.river.jfree.AnnotationHelper; import org.dive4elements.river.jfree.AxisDataset; import org.dive4elements.river.jfree.Bounds; import org.dive4elements.river.jfree.DoubleBounds; +import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledAreaSeriesCollection; import org.dive4elements.river.jfree.XYMetaSeriesCollection; - import org.dive4elements.river.themes.ThemeDocument; - import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.LegendItem; - import org.jfree.chart.annotations.XYAnnotation; import org.jfree.chart.annotations.XYImageAnnotation; - import org.jfree.chart.axis.LogarithmicAxis; import org.jfree.chart.axis.NumberAxis; import org.jfree.chart.axis.ValueAxis; - import org.jfree.chart.plot.Marker; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; - import org.jfree.data.Range; - import org.jfree.data.general.Series; - import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; -import org.w3c.dom.Document; - -import org.apache.commons.lang.StringUtils; - /** * The main diagram creation class. @@ -102,9 +81,9 @@ /** The log that is used in this generator. */ private static Logger log = Logger.getLogger(DiagramGenerator.class); - protected List<Marker> domainMarkers = new ArrayList<Marker>(); + protected List<Marker> domainMarkers = new ArrayList<>(); - protected List<Marker> valueMarkers = new ArrayList<Marker>(); + protected List<Marker> valueMarkers = new ArrayList<>(); /** The max X range to include all X values of all series for each axis. */ protected Map<Integer, Bounds> xBounds; @@ -144,17 +123,7 @@ diagramAttributes = da.new Instance(); } - @Override - public void init( - String outName, - Document request, - OutputStream out, - CallContext context - ) { - super.init(outName, request, out, context); - } - - private void setInvertedFromConfig() { + private void setInvertedFromConfig(CallContext context) { DiagramAttributes.DomainAxisAttributes dx = diagramAttributes.getDomainAxis(); @@ -175,13 +144,13 @@ * Generate the chart anew (including localized axis and all). */ @Override - public JFreeChart generateChart() { + protected JFreeChart generateChart(CallContext context) { log.debug("DiagramGenerator.generateChart"); postProcess(); JFreeChart chart = ChartFactory.createXYLineChart( - getChartTitle(), + getChartTitle(context), "", "", null, @@ -191,13 +160,13 @@ false); XYPlot plot = (XYPlot) chart.getPlot(); - ValueAxis axis = createXAxis(getXAxisLabel()); + ValueAxis axis = createXAxis(context, getXAxisLabel()); plot.setDomainAxis(axis); chart.setBackgroundPaint(Color.WHITE); plot.setBackgroundPaint(Color.WHITE); - addSubtitles(chart); - addMetadataSubtitle(chart); + addSubtitles(context, chart); + addMetadataSubtitle(context, chart); adjustPlot(plot); //debugAxis(plot); @@ -215,7 +184,7 @@ localizeAxes(plot); - setInvertedFromConfig(); + setInvertedFromConfig(context); adjustAxes(plot); if (!(axis instanceof LogarithmicAxis)) { @@ -230,10 +199,8 @@ //debugAxis(plot); // These have to go after the autozoom. - AnnotationHelper.addAnnotationsToRenderer(annotations, plot, - getChartSettings(), datasets); - AnnotationHelper.addYAnnotationsToRenderer(yAnnotations, plot, - getChartSettings(), datasets); + addAnnotationsToRenderer(plot); + addYAnnotationsToRenderer(plot); // Add a logo (maybe). addLogo(plot); @@ -249,10 +216,6 @@ return chart; } - public String getOutName() { - return outName; - } - /** * Return left most data points x value (on first axis). */ @@ -393,7 +356,7 @@ } - protected NumberAxis createXAxis(String label) { + protected NumberAxis createXAxis(final CallContext context, String label) { boolean logarithmic = (Boolean)diagramAttributes.getDomainAxis(). isLog().evaluate((D4EArtifact)getMaster(), context); @@ -1113,7 +1076,7 @@ } @Override - public String getDefaultChartTitle() { + protected final String getDefaultChartTitle(CallContext context) { DiagramAttributes.Title dTitle = diagramAttributes.getTitle(); if (dTitle == null) { return "Title not configured in conf.xml"; @@ -1122,8 +1085,9 @@ return dTitle.evaluate((D4EArtifact)getMaster(), context); } + @Override - public String getDefaultChartSubtitle() { + protected String getDefaultChartSubtitle(CallContext context) { String parts = ""; DiagramAttributes.Title dTitle = diagramAttributes.getSubtitle(); if (dTitle == null && @@ -1154,7 +1118,7 @@ * Get internationalized label for the x axis. */ @Override - protected String getDefaultXAxisLabel() { + protected String getDefaultXAxisLabel(CallContext context) { DiagramAttributes.DomainAxisAttributes dx = diagramAttributes.getDomainAxis(); @@ -1167,8 +1131,7 @@ return "Domain Axis Title not configured in conf.xml"; } - @Override - protected String getDefaultYAxisLabel(String axisName) { + protected final String getDefaultYAxisLabel(String axisName) { Set labelSet = axesLabels.get(diagramAttributes.getAxisIndex(axisName)); log.debug("Labels for axis: " + labelSet); if (labelSet != null && !labelSet.isEmpty()) { @@ -1198,8 +1161,9 @@ * * @return a list of Y axis sections. */ - protected List<AxisSection> buildYAxisSections() { - List<AxisSection> axisSections = new ArrayList<AxisSection>(); + @Override + protected final List<AxisSection> buildYAxisSections() { + List<AxisSection> axisSections = new ArrayList<>(); List<DiagramAttributes.AxisAttributes> axesAttrs = diagramAttributes.getAxesAttributes(); @@ -1315,7 +1279,7 @@ final AxisAttributes axisAttributes = diagramAttributes.getAxesAttributes().get(index); - boolean logarithmic = (Boolean)axisAttributes.isLog().evaluate((D4EArtifact)getMaster(), context); + boolean logarithmic = (Boolean)axisAttributes.isLog().evaluate((D4EArtifact)getMaster(), getContext()); NumberAxis axis; if (logarithmic) { @@ -1347,4 +1311,4 @@ public void addSubtitle(String part) { this.subTitleParts.add(part); } -} +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/DischargeCurveGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DischargeCurveGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -28,6 +28,7 @@ import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.artifactdatabase.state.State; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.GaugeDischargeCurveArtifact; import org.apache.log4j.Logger; @@ -121,8 +122,8 @@ if (getMaster() instanceof GaugeDischargeCurveArtifact) { GaugeDischargeCurveArtifact myMaster = (GaugeDischargeCurveArtifact) getMaster(); - State state = myMaster.getCurrentState(context); - if (myMaster.STATIC_STATE_NAME.equals(state.getID())) { + State state = myMaster.getCurrentState(getContext()); + if (GaugeDischargeCurveArtifact.STATIC_STATE_NAME.equals(state.getID())) { return; } } @@ -213,13 +214,13 @@ * Returns always null to suppress subtitles. */ @Override - protected String getDefaultChartTitle() { + protected String getDefaultChartTitle(final CallContext context) { return null; } @Override - protected String getDefaultXAxisLabel() { + protected String getDefaultXAxisLabel(final CallContext context) { return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); } @@ -278,6 +279,8 @@ String name = artifactFacet.getFacetName(); log.debug("DischargeCurveGenerator.doOut: " + name); + final CallContext context = getContext(); + MiscDischargeProcessor dProcessor = new MiscDischargeProcessor( getRange()[0]); if (dProcessor.canHandle(name)) { @@ -376,8 +379,7 @@ double y, ThemeDocument theme ) { - List<XYTextAnnotation> textAnnos = - new ArrayList<XYTextAnnotation>(); + final List<XYTextAnnotation> textAnnos = new ArrayList<>(); XYTextAnnotation anno = new CollisionFreeXYTextAnnotation( title, x, @@ -429,8 +431,7 @@ // If no Q values (i.e. all -1) found, add annotations. if (hasNoDischarge(data)) { - List<StickyAxisAnnotation> xy = - new ArrayList<StickyAxisAnnotation>(); + final List<StickyAxisAnnotation> xy = new ArrayList<>(); for (double y: data[1]) { if (translate != 0d) {
--- a/artifacts/src/main/java/org/dive4elements/river/exports/DischargeGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DischargeGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -39,7 +39,7 @@ public void addDatasets(XYPlot plot) { super.addDatasets(plot); - Object pnp = context.getContextValue(PNP); + Object pnp = getContext().getContextValue(PNP); if (!(pnp instanceof Number)) { return; } @@ -52,7 +52,7 @@ return; } - AxisDataset data = datasets.get(wAxisIndex); + AxisDataset data = getDatasets().get(wAxisIndex); if (data == null) { // No W axis return; @@ -94,8 +94,7 @@ getYAxisFontSize(wAxisIndex)); String axisName = "W.in.cm"; - String axisLabel = Resources.getMsg(context.getMeta(), - I18N_AXIS_LABEL, "W [cm]"); + String axisLabel = msg( I18N_AXIS_LABEL, "W [cm]" ); IdentifiableNumberAxis axis = new IdentifiableNumberAxis( axisName, axisLabel);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/DurationCurveGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DurationCurveGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -9,6 +9,7 @@ package org.dive4elements.river.exports; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.model.FacetTypes; import org.dive4elements.river.artifacts.model.WQDay; import org.dive4elements.river.jfree.Bounds; @@ -95,13 +96,13 @@ @Override - protected String getDefaultChartTitle() { + protected String getDefaultChartTitle(final CallContext context) { return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); } @Override - protected String getDefaultChartSubtitle() { + protected String getDefaultChartSubtitle(final CallContext context) { double[] dist = getRange(); Object[] args = new Object[] { @@ -114,7 +115,7 @@ @Override - protected String getDefaultXAxisLabel() { + protected String getDefaultXAxisLabel(final CallContext context) { return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); } @@ -123,7 +124,7 @@ protected String getDefaultYAxisLabel(int index) { String label = "default"; if (index == YAXIS.W.idx) { - label = msg(I18N_YAXIS_LABEL_W, new Object[] { getRiverUnit() }); + label = msg(I18N_YAXIS_LABEL_W, I18N_YAXIS_LABEL_W, new Object[] { getRiverUnit() }); } else if (index == YAXIS.Q.idx) { label = msg(I18N_YAXIS_LABEL_Q); @@ -192,6 +193,8 @@ log.error("No facet given. Cannot create dataset."); return; } + + final CallContext context = getContext(); if (name.equals(DURATION_W)) { doWOut(
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ExportSection.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ExportSection.java Tue Jun 05 19:21:16 2018 +0200 @@ -18,13 +18,15 @@ public static final String WIDTH_ATTR = "width"; public static final String HEIGHT_ATTR = "height"; + private static final String METADATA_ATTR = "chart_settings_export_metadata"; + public ExportSection() { super("export"); } - public void setWidth(int width) { + public void setWidth(final int width) { if (width <= 0) { return; } @@ -38,7 +40,7 @@ } - public void setHeight(int height) { + public void setHeight(final int height) { if (height <= 0) { return; } @@ -50,5 +52,12 @@ public Integer getHeight() { return getIntegerValue(HEIGHT_ATTR); } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : + + public void setMetadata(final boolean metadata) { + setBooleanValue(METADATA_ATTR, metadata); + } + + public boolean getMetadata() { + return getBooleanValue(METADATA_ATTR, true); + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeCurveGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/HistoricalDischargeCurveGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -13,7 +13,7 @@ import org.apache.log4j.Logger; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; - +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.access.HistoricalDischargeAccess; @@ -90,13 +90,13 @@ } @Override - protected String getDefaultChartTitle() { + protected String getDefaultChartTitle(final CallContext context) { return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); } @Override - protected String getDefaultChartSubtitle() { - D4EArtifact flys = (D4EArtifact) master; + protected String getDefaultChartSubtitle(final CallContext context) { + D4EArtifact flys = getArtifact(); Timerange evalTime = new HistoricalDischargeAccess(flys) .getEvaluationTimerange(); @@ -107,7 +107,7 @@ } @Override - protected String getDefaultXAxisLabel() { + protected String getDefaultXAxisLabel(final CallContext context) { return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL); } @@ -138,6 +138,8 @@ log.debug("Theme description is: " + artifactFacet.getFacetDescription()); + final CallContext context = getContext(); + if (name.equals(HISTORICAL_DISCHARGE_Q)) { doHistoricalDischargeOutQ( (D4EArtifact) artifactFacet.getArtifact(),
--- a/artifacts/src/main/java/org/dive4elements/river/exports/LegendSection.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/LegendSection.java Tue Jun 05 19:21:16 2018 +0200 @@ -55,8 +55,8 @@ } - public Boolean getVisibility() { - return getBooleanValue(VISIBILITY_ATTR); + public boolean getVisibility() { + return getBooleanValue(VISIBILITY_ATTR, true); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -10,6 +10,7 @@ import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifactdatabase.state.Facet; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.geom.Lines; import org.dive4elements.river.artifacts.model.AreaFacet; @@ -157,18 +158,17 @@ * @return the default title for this chart. */ @Override - public String getDefaultChartTitle() { + public String getDefaultChartTitle(final CallContext context) { return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); } - /** * Returns the default subtitle for this chart. * * @return the default subtitle for this chart. */ @Override - protected String getDefaultChartSubtitle() { + protected String getDefaultChartSubtitle(final CallContext context) { double[] dist = getRange(); Object[] args = null; @@ -208,8 +208,8 @@ * Get internationalized label for the x axis. */ @Override - protected String getDefaultXAxisLabel() { - D4EArtifact flys = (D4EArtifact) master; + protected String getDefaultXAxisLabel(CallContext context) { + D4EArtifact flys = getArtifact(); return msg( I18N_XAXIS_LABEL, @@ -241,7 +241,7 @@ * Get internationalized label for the y axis. */ protected String getWAxisLabel() { - D4EArtifact flys = (D4EArtifact) master; + D4EArtifact flys = getArtifact(); String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); @@ -340,6 +340,8 @@ return; } + CallContext context = getContext(); + Processor wProcessor = new WOutProcessor(); Processor qProcessor = new QOutProcessor(); Processor bdyProcessor = new BedDiffYearProcessor();
--- a/artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator2.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/LongitudinalSectionGenerator2.java Tue Jun 05 19:21:16 2018 +0200 @@ -10,6 +10,7 @@ import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.jfree.Bounds; import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.artifacts.model.FacetTypes; @@ -62,7 +63,7 @@ "chart.subtitle.radius"; @Override - public String getDefaultChartSubtitle() { + public String getDefaultChartSubtitle(final CallContext context) { double[] dist = getRange(); String parts = ""; @@ -124,6 +125,7 @@ // This might not be neccessary if every facet uses only the // radius and does not do its own zoomscale calculation. + final CallContext context = getContext(); context.putContextValue("startkm", candidate.getLowerBound()); context.putContextValue("endkm", candidate.getUpperBound()); context.putContextValue("bounds_defined", true); @@ -146,6 +148,7 @@ } // fake startkm and endkm for the dry run + final CallContext context = getContext(); context.putContextValue("startkm", 0d); context.putContextValue("endkm", 42d); for (SuperBundle superbundle: postOutAF) { @@ -185,15 +188,13 @@ SuperBundle superbundle = new SuperBundle(bundle, theme, visible); if (postOutAF == null) { - postOutAF = new ArrayList<SuperBundle>(); + postOutAF = new ArrayList<>(); } postOutAF.add(superbundle); if (visible) { log.debug("Adding radius subtitle."); - addSubtitle(Resources.getMsg( - getCallContext().getMeta(), - I18N_SUBTITLE_RADIUS) + ": $RADIUS"); + addSubtitle(msg(I18N_SUBTITLE_RADIUS) + ": $RADIUS"); } return; }
--- a/artifacts/src/main/java/org/dive4elements/river/exports/NormalizedReferenceCurveGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/NormalizedReferenceCurveGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -8,6 +8,8 @@ package org.dive4elements.river.exports; +import org.dive4elements.artifacts.CallContext; + /** * An OutGenerator that generates reference curves. */ @@ -25,7 +27,7 @@ /** Get default chart title. */ @Override - protected String getDefaultChartTitle() { + protected String getDefaultChartTitle(final CallContext context) { return msg( I18N_NORMALIZED_CHART_TITLE, I18N_NORMALIZED_CHART_TITLE_DEFAULT);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ReferenceCurveGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ReferenceCurveGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -9,6 +9,7 @@ package org.dive4elements.river.exports; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.model.FacetTypes; import org.dive4elements.river.artifacts.model.WW; import org.dive4elements.river.artifacts.model.WW.ApplyFunctionIterator; @@ -86,12 +87,12 @@ /** Get default chart title. */ @Override - protected String getDefaultChartTitle() { + protected String getDefaultChartTitle(final CallContext context) { return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); } @Override - protected String getDefaultChartSubtitle() { + protected String getDefaultChartSubtitle(final CallContext context) { Object[] args = new Object[] { getRiverName(), }; @@ -102,14 +103,14 @@ /** True if axis is in cm (because at gauge). */ protected boolean getInCm(int index) { - Object obj = context.getContextValue("reference.curve.axis.scale"); + Object obj = getContext().getContextValue("reference.curve.axis.scale"); return obj instanceof WWAxisTypes && ((WWAxisTypes)obj).getInCm(index); } /** Get Label for X-axis (W). */ @Override - protected String getDefaultXAxisLabel() { + protected String getDefaultXAxisLabel(final CallContext context) { return msg(getInCm(0) ? I18N_X_AXIS_IN_CM : I18N_X_AXIS_IN_M); } @@ -149,6 +150,8 @@ return; } + final CallContext context = getContext(); + if (name.equals(facetName())) { doReferenceOut(artifactFacet.getData(context), theme, visible); } @@ -194,7 +197,7 @@ ) { WW ww = (WW)data; - Object obj = context.getContextValue("reference.curve.axis.scale"); + Object obj = getContext().getContextValue("reference.curve.axis.scale"); WWAxisTypes wwat = obj instanceof WWAxisTypes ? (WWAxisTypes)obj @@ -236,7 +239,7 @@ /** Set the tick units for given axis. */ protected void setAxisTickUnit(double tick, ValueAxis axis) { TickUnits units = new TickUnits(); - units.add(new NumberTickUnit(tick, Formatter.getWaterlevelW(context))); + units.add(new NumberTickUnit(tick, Formatter.getWaterlevelW(getContext()))); axis.setStandardTickUnits(units); axis.setAutoTickUnitSelection(true); }
--- a/artifacts/src/main/java/org/dive4elements/river/exports/TimeseriesChartGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/TimeseriesChartGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -9,12 +9,12 @@ package org.dive4elements.river.exports; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.jfree.Bounds; import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation; import org.dive4elements.river.jfree.DoubleBounds; import org.dive4elements.river.jfree.RiverAnnotation; -import org.dive4elements.river.jfree.AnnotationHelper; import org.dive4elements.river.jfree.StyledTimeSeries; import org.dive4elements.river.jfree.TimeBounds; import org.dive4elements.river.jfree.AxisDataset; @@ -93,14 +93,12 @@ attributes = new HashMap<String, String>(); } - - @Override - public JFreeChart generateChart() { + protected JFreeChart generateChart(CallContext context) { log.info("Generate Timeseries Chart."); JFreeChart chart = ChartFactory.createTimeSeriesChart( - getChartTitle(), + getChartTitle(context), getXAxisLabel(), getYAxisLabel(0), null, @@ -113,8 +111,8 @@ chart.setBackgroundPaint(Color.WHITE); plot.setBackgroundPaint(Color.WHITE); - addSubtitles(chart); - addMetadataSubtitle( chart ); + addSubtitles(context, chart); + addMetadataSubtitle( context, chart ); adjustPlot(plot); addDatasets(plot); adjustAxes(plot); @@ -126,11 +124,8 @@ consumeAxisSettings(plot); - AnnotationHelper.addAnnotationsToRenderer( - annotations, - plot, - getChartSettings(), - datasets); + addAnnotationsToRenderer(plot); + addLogo(plot); aggregateLegendEntries(plot); return chart; @@ -629,7 +624,7 @@ catch(JSONException ex) { String str = array.getString(0); DateFormat df = DateFormat.getDateInstance( - DateFormat.MEDIUM, Resources.getLocale(context.getMeta())); + DateFormat.MEDIUM, Resources.getLocale(getContext().getMeta())); return df.parse(str); } } @@ -856,7 +851,7 @@ * setLowerTimeRange */ @Override protected List<AxisSection> buildXAxisSections() { - List<AxisSection> axisSections = new ArrayList<AxisSection>(); + List<AxisSection> axisSections = new ArrayList<>(); String identifier = "X";
--- a/artifacts/src/main/java/org/dive4elements/river/exports/TypeSection.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/TypeSection.java Tue Jun 05 19:21:16 2018 +0200 @@ -123,26 +123,25 @@ } - public void setBooleanValue(String key, boolean value) { - Attribute attr = getAttribute(key); - if (attr == null) { - attr = new BooleanAttribute(key, value, true); - addAttribute(key, attr); - } - else { + protected final void setBooleanValue(String key, boolean value) { + final Attribute attr = getAttribute(key); + if (attr == null) + addAttribute(key, new BooleanAttribute(key, value, true)); + else attr.setValue(value); - } } - - public Boolean getBooleanValue(String key) { - Attribute attr = getAttribute(key); + protected final boolean getBooleanValue(final String key, boolean defaultValue) { + final Attribute attr = getAttribute(key); if (attr instanceof BooleanAttribute) { - return (Boolean) attr.getValue(); + final Boolean value = (Boolean) attr.getValue(); + if( value == null ) + return defaultValue; + + return value; } - return null; + return defaultValue; } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -40,6 +40,7 @@ import org.json.JSONException; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.jfree.Bounds; import org.dive4elements.river.jfree.CollisionFreeXYTextAnnotation; import org.dive4elements.river.jfree.DoubleBounds; @@ -47,7 +48,6 @@ import org.dive4elements.river.jfree.StyledAreaSeriesCollection; import org.dive4elements.river.jfree.StyledXYSeries; import org.dive4elements.river.jfree.AxisDataset; -import org.dive4elements.river.jfree.AnnotationHelper; import org.dive4elements.river.themes.ThemeDocument; @@ -102,11 +102,11 @@ * Generate the chart anew (including localized axis and all). */ @Override - public JFreeChart generateChart() { + protected JFreeChart generateChart(CallContext context) { log.debug("XYChartGenerator.generateChart"); JFreeChart chart = ChartFactory.createXYLineChart( - getChartTitle(), + getChartTitle(context), getXAxisLabel(), getYAxisLabel(0), null, @@ -121,8 +121,8 @@ chart.setBackgroundPaint(Color.WHITE); plot.setBackgroundPaint(Color.WHITE); - addSubtitles(chart); - addMetadataSubtitle(chart); + addSubtitles(context, chart); + addMetadataSubtitle(context, chart); adjustPlot(plot); //debugAxis(plot); @@ -994,10 +994,5 @@ public void setInverted(boolean inverted) { this.inverted = inverted; } - - protected void addAnnotationsToRenderer(XYPlot plot) { - AnnotationHelper.addAnnotationsToRenderer(annotations, plot, - getChartSettings(), datasets); - } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/exports/extreme/ExtremeWQCurveGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/extreme/ExtremeWQCurveGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -19,6 +19,7 @@ import org.jfree.data.xy.XYSeries; import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.access.FixAnalysisAccess; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.model.DateRange; @@ -114,7 +115,7 @@ ) { log.debug("doExtremeCurveBaseOut"); ExtremeCurveFacet facet = (ExtremeCurveFacet) aaf.getFacet(); - Curve curve = (Curve) facet.getData(aaf.getArtifact(), context); + Curve curve = (Curve) facet.getData(aaf.getArtifact(), getContext()); if (curve == null) { log.warn("doExtremeCurveBaseOut: Facet does not contain Curve"); return; @@ -155,7 +156,7 @@ ) { log.debug("doExtremeCurveOut"); ExtremeCurveFacet facet = (ExtremeCurveFacet) aaf.getFacet(); - Curve curve = (Curve) facet.getData(aaf.getArtifact(), context); + Curve curve = (Curve) facet.getData(aaf.getArtifact(), getContext()); if (curve == null) { log.warn("doExtremeCurveOut: Facet does not contain Curve"); return; @@ -189,29 +190,29 @@ @Override - protected String getChartTitle() { + protected String getChartTitle(final CallContext context) { return Resources.format( - context.getMeta(), + getContext().getMeta(), I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT, - context.getContextValue(CURRENT_KM)); + getContext().getContextValue(CURRENT_KM)); } @Override - protected String getDefaultChartTitle() { + protected String getDefaultChartTitle(final CallContext context) { return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); } @Override - protected String getDefaultChartSubtitle() { + protected String getDefaultChartSubtitle(final CallContext context) { FixAnalysisAccess access = new FixAnalysisAccess(artifact); DateRange dateRange = access.getDateRange(); DateRange refRange = access.getReferencePeriod(); if (dateRange != null && refRange != null) { return Resources.format( - context.getMeta(), + getContext().getMeta(), I18N_CHART_SUBTITLE, "", access.getRiverName(), @@ -225,8 +226,8 @@ } @Override - protected void addSubtitles(JFreeChart chart) { - String defaultSubtitle = getDefaultChartSubtitle(); + protected void addSubtitles(final CallContext context, JFreeChart chart) { + String defaultSubtitle = getDefaultChartSubtitle(context); if (defaultSubtitle == null || defaultSubtitle.length() == 0) { return; @@ -236,13 +237,13 @@ } @Override - protected String getDefaultXAxisLabel() { + protected String getDefaultXAxisLabel(final CallContext context) { return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); } @Override protected String getDefaultYAxisLabel(int pos) { - D4EArtifact flys = (D4EArtifact) master; + D4EArtifact flys = getArtifact(); String unit = RiverUtils.getRiver(flys).getWstUnit().getName(); if (pos == 0) {
--- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixDeltaWtGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixDeltaWtGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -106,24 +106,24 @@ @Override - protected String getDefaultChartTitle() { + protected String getDefaultChartTitle(final CallContext context) { return msg(I18N_CHART_TITLE, I18N_CHART_TITLE); } @Override - protected String getChartTitle() { + protected String getChartTitle(final CallContext context) { return Resources.format( context.getMeta(), I18N_CHART_TITLE, "", FixChartGenerator - .getCurrentKmFromRequest(request).doubleValue()); + .getCurrentKmFromRequest(getRequest()).doubleValue()); } @Override - protected String getDefaultChartSubtitle() { + protected String getDefaultChartSubtitle(final CallContext context) { FixAnalysisAccess access = new FixAnalysisAccess(artifact); DateRange dateRange = access.getDateRange(); DateRange refRange = access.getReferencePeriod(); @@ -140,7 +140,7 @@ @Override - protected String getDefaultXAxisLabel() { + protected String getDefaultXAxisLabel(final CallContext context) { return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL); } @@ -171,6 +171,8 @@ this.artifact = (D4EArtifact)artifactFacet.getArtifact(); + final CallContext context = getContext(); + if (name.contains(FIX_SECTOR_AVERAGE_DWT)) { doSectorAverageOut( (D4EArtifact) artifactFacet.getArtifact(), @@ -388,10 +390,10 @@ return; } - Locale locale = Resources.getLocale(context.getMeta()); + Locale locale = Resources.getLocale(getContext().getMeta()); NumberFormat nf = NumberFormat.getInstance(locale); - List<XYTextAnnotation> textAnnos = new ArrayList<XYTextAnnotation>(); + List<XYTextAnnotation> textAnnos = new ArrayList<>(); for (int[] idxs: annoIdxMap.values()) {
--- a/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixWQCurveGenerator.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/fixings/FixWQCurveGenerator.java Tue Jun 05 19:21:16 2018 +0200 @@ -28,6 +28,7 @@ import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; import org.dive4elements.artifactdatabase.state.Facet; +import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.StaticWKmsArtifact; import org.dive4elements.river.artifacts.WINFOArtifact; @@ -115,7 +116,7 @@ /** Returns value != 0 if the current km is not at a gauge. */ public double getCurrentGaugeDatum() { - Object ckm = context.getContextValue(CURRENT_KM); + Object ckm = getContext().getContextValue(CURRENT_KM); if (ckm != null) { return DischargeCurveGenerator.getCurrentGaugeDatum( (Double) ckm, @@ -210,6 +211,8 @@ this.artifact = (D4EArtifact) aaf.getArtifact(); + final CallContext context = getContext(); + if(name.startsWith(FIX_SECTOR_AVERAGE_WQ)) { doSectorAverageOut(aaf, doc, visible); } @@ -286,7 +289,7 @@ ) { log.debug("doSectorAverageOut"); - QWDDateRange qwdd = (QWDDateRange) aaf.getData(context); + QWDDateRange qwdd = (QWDDateRange) aaf.getData(getContext()); QWD qwd = qwdd != null ? qwdd.getQWD() : null; if(qwd != null) { @@ -305,7 +308,7 @@ ) { log.debug("doAnalysisEventsOut"); - QWD qwd = (QWD)aaf.getData(context); + QWD qwd = (QWD)aaf.getData(getContext()); if (qwd == null) { log.debug("doAnalysisEventsOut: qwd == null"); @@ -365,7 +368,7 @@ ) { log.debug("doReferenceEventsOut"); - QWI qwd = (QWI)aaf.getData(context); + QWI qwd = (QWI)aaf.getData(getContext()); if (qwd == null) { log.debug("doReferenceEventsOut: qwds == null"); return; @@ -421,7 +424,7 @@ boolean visible ) { XYSeries series = new StyledXYSeries(title, theme); - Double ckm = (Double) context.getContextValue(CURRENT_KM); + Double ckm = (Double) getContext().getContextValue(CURRENT_KM); if (wqkms == null || wqkms.getKms().length == 0 || ckm == null) { log.info("addPointFromWQKms: No event data to show."); return; @@ -458,7 +461,7 @@ ) { log.debug("doEventsOut"); // Find W/Q at km. - addPointFromWQKms((WQKms) aaf.getData(context), + addPointFromWQKms((WQKms) aaf.getData(getContext()), aaf.getFacetDescription(), doc, visible); } @@ -472,7 +475,7 @@ FixWQCurveFacet facet = (FixWQCurveFacet)aaf.getFacet(); FixFunction func = (FixFunction)facet.getData( - aaf.getArtifact(), context); + aaf.getArtifact(), getContext()); if (func == null) { log.warn("doWQCurveOut: Facet does not contain FixFunction"); @@ -527,7 +530,7 @@ ) { log.debug("doOutlierOut"); - QWI[] qws = (QWI[])aaf.getData(context); + QWI[] qws = (QWI[])aaf.getData(getContext()); addQWSeries(qws, aaf, doc, visible); } @@ -543,7 +546,7 @@ return; } - Object qsectorsObj = aaf.getData(context); + Object qsectorsObj = aaf.getData(getContext()); if (qsectorsObj == null || !(qsectorsObj instanceof List)) { log.warn("No QSectors coming from data."); return; @@ -631,7 +634,7 @@ log.debug("Got WKms"); WKms data = (WKms) wqkms; - Double ckm = (Double) context.getContextValue(CURRENT_KM); + Double ckm = (Double) getContext().getContextValue(CURRENT_KM); double location = (ckm != null) ? ckm.doubleValue() : getRange()[0]; @@ -709,7 +712,7 @@ // be delivered by the facet already (instead of in the Generator). log.debug("FixWQCurveGenerator: doWQOut: WQKms"); - addPointFromWQKms((WQKms)aaf.getData(context), + addPointFromWQKms((WQKms)aaf.getData(getContext()), aaf.getFacetDescription(), theme, visible); } else { @@ -773,7 +776,7 @@ } @Override - protected String getChartTitle() { + protected String getChartTitle(final CallContext context) { return Resources.format( context.getMeta(), I18N_CHART_TITLE, @@ -782,12 +785,12 @@ } @Override - protected String getDefaultChartTitle() { + protected String getDefaultChartTitle(final CallContext context) { return msg(I18N_CHART_TITLE, I18N_CHART_TITLE_DEFAULT); } @Override - protected String getDefaultChartSubtitle() { + protected String getDefaultChartSubtitle(final CallContext context) { FixAnalysisAccess access = new FixAnalysisAccess(artifact); DateRange dateRange = access.getDateRange(); DateRange refRange = access.getReferencePeriod(); @@ -808,8 +811,8 @@ } @Override - protected void addSubtitles(JFreeChart chart) { - String defaultSubtitle = getDefaultChartSubtitle(); + protected void addSubtitles(final CallContext context, final JFreeChart chart) { + String defaultSubtitle = getDefaultChartSubtitle(getContext()); if (defaultSubtitle == null || defaultSubtitle.length() == 0) { return; @@ -841,13 +844,13 @@ } @Override - protected String getDefaultXAxisLabel() { + protected String getDefaultXAxisLabel(final CallContext context) { return msg(I18N_XAXIS_LABEL, I18N_XAXIS_LABEL_DEFAULT); } @Override protected String getDefaultYAxisLabel(int pos) { - D4EArtifact flys = (D4EArtifact) master; + D4EArtifact flys = getArtifact(); String unit = pos == 0 ? "cm"
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/AnnotationProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/AnnotationProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -38,7 +38,7 @@ // Nothing to do return; } - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); if (!(bundle.getData(context) instanceof RiverAnnotation)) { // Just a bit defensive should not happen log.error("Incompatible facet in doOut"); @@ -62,7 +62,7 @@ // Nothing to do return; } - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); if (!(bundle.getData(context) instanceof RiverAnnotation)) { // Just a bit defensive should not happen log.error("Incompatible facet in doOut");
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/AreaProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/AreaProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -83,7 +83,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); String seriesName = bundle.getFacetDescription(); StyledAreaSeriesCollection area = new StyledAreaSeriesCollection(theme);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffHeightYearProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffHeightYearProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -43,7 +43,7 @@ ThemeDocument theme, boolean visible ) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Object data = bundle.getData(context); Map<String, String> metaData = bundle.getFacet().getMetaData( bundle.getArtifact(), context); @@ -74,7 +74,7 @@ boolean visible, int index ) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Object data = bundle.getData(context); if (!(data instanceof double[][])) {
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffYearProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedDiffYearProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -42,7 +42,7 @@ ThemeDocument theme, boolean visible ) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Map<String, String> metaData = bundle.getFacet().getMetaData(bundle.getArtifact(), context); yAxisLabel = metaData.get("Y");
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedHeightProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedHeightProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -50,7 +50,7 @@ ThemeDocument theme, boolean visible) { XYSeries series = prepareSeries( - bundle, theme, generator.getCallContext()); + bundle, theme, generator.getContext()); if (series != null) { generator.addAxisSeries(series, axisName, visible); } @@ -65,7 +65,7 @@ int index ) { XYSeries series = prepareSeries( - bundle, theme, generator.getCallContext()); + bundle, theme, generator.getContext()); if (series != null) { generator.addAxisSeries(series, index, visible); } @@ -120,7 +120,7 @@ D4EArtifact flys = (D4EArtifact) generator.getMaster(); String unit = new RiverAccess(flys).getRiver().getWstUnit().getName(); - CallMeta meta = generator.getCallContext().getMeta(); + CallMeta meta = generator.getContext().getMeta(); if (yAxisLabel != null && !yAxisLabel.isEmpty()) { return Resources.getMsg(
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityDensityProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityDensityProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -37,7 +37,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); Map<String, String> metaData = bundle.getFacet().getMetaData(); @@ -69,7 +69,7 @@ @Override public String getAxisLabel(DiagramGenerator generator) { - CallMeta meta = generator.getCallContext().getMeta(); + CallMeta meta = generator.getContext().getMeta(); if (yAxisLabel != null && !yAxisLabel.isEmpty()) { return Resources.getMsg(meta, yAxisLabel);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityDiameterProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityDiameterProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -37,7 +37,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Map<String, String> metaData = bundle.getFacet().getMetaData(); StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); @@ -71,7 +71,7 @@ @Override public String getAxisLabel(DiagramGenerator generator) { - CallMeta meta = generator.getCallContext().getMeta(); + CallMeta meta = generator.getContext().getMeta(); if (yAxisLabel != null && !yAxisLabel.isEmpty()) { return Resources.getMsg(meta, yAxisLabel);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityPorosityProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedQualityPorosityProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -37,7 +37,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Map<String, String> metaData = bundle.getFacet().getMetaData(); StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/BedWidthProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/BedWidthProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -41,7 +41,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Map<String, String> metaData = bundle.getFacet().getMetaData(); StyledXYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/DeltaWProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/DeltaWProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -88,7 +88,7 @@ private void doSectorAverageOut(DiagramGenerator generator, ArtifactAndFacet bundle, ThemeDocument doc, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); int index = bundle.getFacet().getIndex(); int sectorNdx = index & 3; @@ -118,7 +118,7 @@ private void doReferenceEventsOut(DiagramGenerator generator, ArtifactAndFacet bundle, ThemeDocument doc, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); KMIndex<QWD> kms = (KMIndex<QWD>)bundle.getData(context); @@ -148,7 +148,7 @@ ArtifactAndFacet bundle, ThemeDocument doc, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); KMIndex<QWD> kms = (KMIndex<QWD>)bundle.getData(context); @@ -178,7 +178,7 @@ ArtifactAndFacet bundle, ThemeDocument doc, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); int index = bundle.getFacet().getIndex(); int sectorNdx = index & 3; @@ -221,7 +221,7 @@ ArtifactAndFacet bundle, ThemeDocument doc, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); KMIndex<double[]> kms = (KMIndex<double[]>)bundle.getData(context);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/DischargeProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/DischargeProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -60,7 +60,7 @@ ThemeDocument theme, boolean visible ) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Object data = bundle.getData(context); if (data instanceof WQKms) { doDischargeOut( @@ -99,7 +99,7 @@ ThemeDocument theme, boolean visible ) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Map<String, String> metaData = bundle.getFacet().getMetaData( bundle.getArtifact(), context); WQKms data = (WQKms)bundle.getData(context); @@ -123,7 +123,7 @@ @Override public String getAxisLabel(DiagramGenerator generator) { - CallMeta meta = generator.getCallContext().getMeta(); + CallMeta meta = generator.getContext().getMeta(); RiverAccess access = new RiverAccess((D4EArtifact)generator.getMaster()); String unit = access.getRiver().getWstUnit().getName();
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWAProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWAProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -39,7 +39,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Object data = bundle.getData(context); XYSeries series = new StyledXYSeries(
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDeltaWProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -39,7 +39,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Object data = bundle.getData(context); XYSeries series = new StyledXYSeries(
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDerivedProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/FixDerivedProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -48,12 +48,12 @@ ThemeDocument theme, boolean visible ) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Map<String, String> metaData = bundle.getFacet().getMetaData( bundle.getArtifact(), context); FixDerivateFacet facet = (FixDerivateFacet)bundle.getFacet(); FixFunction func = (FixFunction)facet.getData( - bundle.getArtifact(), generator.getCallContext()); + bundle.getArtifact(), generator.getContext()); yAxisLabel = metaData.get("Y"); @@ -86,7 +86,7 @@ @Override public String getAxisLabel(DiagramGenerator generator) { - CallMeta meta = generator.getCallContext().getMeta(); + CallMeta meta = generator.getContext().getMeta(); RiverAccess access = new RiverAccess((D4EArtifact)generator.getMaster()); String unit = access.getRiver().getWstUnit().getName();
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/FixWQProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/FixWQProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -111,7 +111,7 @@ ) { log.debug("doSectorAverageOut"); QWDDateRange qwdd = (QWDDateRange)bundle.getData( - generator.getCallContext()); + generator.getContext()); QWD qwd = qwdd != null ? qwdd.getQWD() : null; if(qwd != null) { @@ -154,7 +154,7 @@ ) { log.debug("doAnalysisEventsOut"); - QWD qwd = (QWD)bundle.getData(generator.getCallContext()); + QWD qwd = (QWD)bundle.getData(generator.getContext()); if (qwd == null) { log.debug("doAnalysisEventsOut: qwd == null"); @@ -206,7 +206,7 @@ boolean visible) { log.debug("doReferenceEventsOut"); - QWI qwd = (QWI)bundle.getData(generator.getCallContext()); + QWI qwd = (QWI)bundle.getData(generator.getContext()); if (qwd == null) { log.debug("doReferenceEventsOut: qwds == null in " + bundle.getFacetDescription()); @@ -259,7 +259,7 @@ FixWQCurveFacet facet = (FixWQCurveFacet)bundle.getFacet(); FixFunction func = (FixFunction)facet.getData( - bundle.getArtifact(), generator.getCallContext()); + bundle.getArtifact(), generator.getContext()); if (func == null) { log.warn("doWQCurveOut: Facet does not contain FixFunction"); @@ -292,7 +292,7 @@ ) { log.debug("doOutlierOut"); - QWI[] qws = (QWI[])bundle.getData(generator.getCallContext()); + QWI[] qws = (QWI[])bundle.getData(generator.getContext()); if(qws != null) { XYSeries series = new StyledXYSeries( bundle.getFacetDescription(), @@ -338,7 +338,7 @@ return; } - Object qsectorsObj = bundle.getData(generator.getCallContext()); + Object qsectorsObj = bundle.getData(generator.getContext()); if (qsectorsObj == null || !(qsectorsObj instanceof List)) { log.warn("No QSectors coming from data."); return; @@ -405,7 +405,7 @@ ThemeDocument theme, boolean visible ) { - Object data = bundle.getData(generator.getCallContext()); + Object data = bundle.getData(generator.getContext()); List<StickyAxisAnnotation> xy = new ArrayList<StickyAxisAnnotation>(); if (data instanceof double[][]) { log.debug("Got double[][]"); @@ -430,7 +430,7 @@ WKms wkms = (WKms) data; Double ckm = - (Double)generator.getCallContext().getContextValue( + (Double)generator.getContext().getContextValue( FixChartGenerator.CURRENT_KM); double location = (ckm != null) ? ckm.doubleValue() @@ -454,14 +454,14 @@ ThemeDocument theme, boolean visible ) { - Object data = bundle.getData(generator.getCallContext()); + Object data = bundle.getData(generator.getContext()); if (data instanceof WQKms) { WQKms wqkms = (WQKms)data; // TODO As in doEventsOut, the value-searching should // be delivered by the facet already XYSeries series = new StyledXYSeries( bundle.getFacetDescription(), theme); - Double ckm = (Double) generator.getCallContext() + Double ckm = (Double) generator.getContext() .getContextValue(CURRENT_KM); if (wqkms == null || wqkms.getKms().length == 0 || ckm == null) { @@ -525,7 +525,7 @@ @Override public String getAxisLabel(DiagramGenerator generator) { - CallMeta meta = generator.getCallContext().getMeta(); + CallMeta meta = generator.getContext().getMeta(); RiverAccess access = new RiverAccess((D4EArtifact)generator .getMaster());
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/FlowVelocityProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/FlowVelocityProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -41,7 +41,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Map<String, String> metaData = bundle.getFacet().getMetaData(); StyledXYSeries series = new StyledXYSeries( bundle.getFacetDescription(),
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/ManualPointsProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/ManualPointsProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -40,7 +40,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); String seriesName = bundle.getFacetDescription(); XYSeries series = new StyledXYSeries(seriesName, theme); String jsonData = (String) bundle.getData(context);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/MiddleBedHeightProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/MiddleBedHeightProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -43,7 +43,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Map<String, String> metaData = bundle.getFacet().getMetaData(); yAxisLabel = metaData.get("Y");
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/MiscDischargeProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/MiscDischargeProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -66,7 +66,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Object data = bundle.getData(context); if (HISTORICAL_DISCHARGE_WQ_Q.equals(bundle.getFacetName())) { doHistoricalDischargeOutQ(generator, bundle, theme, visible); @@ -108,7 +108,7 @@ boolean visible, int axisIndex ) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Object data = bundle.getData(context); /* TODO: Remove the first case.*/ if (bundle.getFacetName().equals(STATIC_WQ)) { @@ -145,7 +145,7 @@ ) { XYSeries series = new StyledXYSeries( bundle.getFacetDescription(), theme); - Object wq = bundle.getData(generator.getCallContext()); + Object wq = bundle.getData(generator.getContext()); if (wq instanceof double[][]) { double [][] data = (double [][]) wq; StyledSeriesBuilder.addPoints(series, data, true); @@ -278,7 +278,7 @@ boolean visible ) { double value = Double.valueOf( - bundle.getData(generator.getCallContext()).toString()); + bundle.getData(generator.getContext()).toString()); generator.addDomainMarker( new StyledValueMarker(value, theme), visible); } @@ -290,7 +290,7 @@ boolean visible ) { double value = Double.valueOf( - bundle.getData(generator.getCallContext()).toString()); + bundle.getData(generator.getContext()).toString()); generator.addValueMarker( new StyledValueMarker(value, theme), visible); } @@ -373,7 +373,7 @@ @Override public String getAxisLabel(DiagramGenerator generator) { - CallMeta meta = generator.getCallContext().getMeta(); + CallMeta meta = generator.getContext().getMeta(); RiverAccess access = new RiverAccess((D4EArtifact)generator .getMaster()); String unit = access.getRiver().getWstUnit().getName();
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/QOutProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/QOutProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -47,7 +47,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Object data = bundle.getData(context); XYSeries series = new StyledXYSeries( bundle.getFacetDescription(), theme); @@ -81,7 +81,7 @@ boolean visible, int index) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); WQKms wqkms = (WQKms) bundle.getData(context); XYSeries series = new StyledXYSeries(
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/SQRelationProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/SQRelationProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -47,7 +47,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); String facetName = bundle.getFacetName(); StyledXYSeries series; Object data = bundle.getData(context);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/SedimentDensityProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/SedimentDensityProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -41,7 +41,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); Object data = bundle.getData(context);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/SedimentLoadLSProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/SedimentLoadLSProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -31,7 +31,7 @@ ThemeDocument theme, boolean visible) { log.debug("doOut " + bundle.getFacetName()); - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), false, // Handle NaN theme);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/SedimentLoadProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/SedimentLoadProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -41,7 +41,7 @@ ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), false, // Handle NaN theme);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/ShearStressProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/ShearStressProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -37,7 +37,7 @@ ArtifactAndFacet bundle, ThemeDocument theme, boolean visible) { - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); XYSeries series = new StyledXYSeries(bundle.getFacetDescription(), theme); String facetName = bundle.getFacetName();
--- a/artifacts/src/main/java/org/dive4elements/river/exports/process/WOutProcessor.java Tue Jun 05 19:10:38 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/process/WOutProcessor.java Tue Jun 05 19:21:16 2018 +0200 @@ -50,7 +50,7 @@ boolean visible ) { log.debug("Processing facet: " + bundle.getFacetName()); - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); Object data = bundle.getData(context); XYSeries series = new StyledXYSeries( @@ -128,7 +128,7 @@ { log.debug("doOut"); - CallContext context = generator.getCallContext(); + CallContext context = generator.getContext(); XYSeries series = new StyledXYSeries( bundle.getFacetDescription(), theme);
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/AnnotationHelper.java Tue Jun 05 19:10:38 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,413 +0,0 @@ -/* 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.jfree; - -import org.dive4elements.river.themes.ThemeDocument; - -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.SortedMap; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Font; - -import org.jfree.ui.TextAnchor; -import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.LegendItem; -import org.jfree.chart.LegendItemCollection; -import org.jfree.chart.annotations.XYTextAnnotation; -import org.jfree.chart.annotations.XYLineAnnotation; -import org.jfree.chart.renderer.xy.XYItemRenderer; - -import org.dive4elements.river.themes.LineStyle; -import org.dive4elements.river.themes.TextStyle; -import org.dive4elements.river.exports.ChartSettings; -import org.dive4elements.river.exports.LegendSection; -import org.dive4elements.river.exports.ChartArea; - -import org.apache.log4j.Logger; - -/** Annotation helper class, handles plotting of annotations. */ -public class AnnotationHelper { - private static final Logger log = Logger.getLogger(AnnotationHelper.class); - - protected static float ANNOTATIONS_AXIS_OFFSET = 0.02f; - - /* arr this would be better in chartsettings */ - public static final int DEFAULT_FONT_SIZE = 12; - public static final String DEFAULT_FONT_NAME = "Tahoma"; - - - public static void addYAnnotationsToRenderer( - SortedMap<Integer, RiverAnnotation> yAnnotations, - XYPlot plot, - ChartSettings settings, - Map<Integer, AxisDataset> datasets - ) { - List<RiverAnnotation> annotations = new ArrayList<RiverAnnotation>(); - - for (Map.Entry<Integer, RiverAnnotation> entry: - yAnnotations.entrySet()) { - int axis = entry.getKey(); - AxisDataset dataset = datasets.get(new Integer(axis)); - - if (dataset == null || dataset.getRange() == null) { - log.warn("No dataset available and active for axis " + axis); - } - else { - RiverAnnotation ya = entry.getValue(); - for (StickyAxisAnnotation sta: ya.getAxisTextAnnotations()) { - sta.setAxisSymbol(axis); - } - annotations.add(ya); - } - } - - addAnnotationsToRenderer(annotations, plot, settings, datasets); - } - - /** - * Add annotations (Sticky, Text and hyk zones) to a plot. - * @param annotations Annotations to add - * @param plot XYPlot to add annotations to. - * @param settings ChartSettings object for settings. - * @param datasets Map of axis index and datasets - */ - public static void addAnnotationsToRenderer( - List<RiverAnnotation> annotations, - XYPlot plot, - ChartSettings settings, - Map<Integer, AxisDataset> datasets - ) { - if (annotations == null || annotations.isEmpty()) { - log.debug("addAnnotationsToRenderer: no annotations."); - return; - } - - // OPTMIMIZE: Pre-calculate positions - ChartArea area = new ChartArea( - plot.getDomainAxis(0), - plot.getRangeAxis()); - - // Walk over all Annotation sets. - for (RiverAnnotation fa: annotations) { - - // Access text styling, if any. - ThemeDocument theme = fa.getTheme(); - TextStyle textStyle = null; - LineStyle lineStyle = null; - - // Get Theming information and add legend item. - if (theme != null) { - textStyle = theme.parseComplexTextStyle(); - lineStyle = theme.parseComplexLineStyle(); - if (fa.getLabel() != null) { - // Legend handling, maybe misplaced? - LegendItemCollection lic = new LegendItemCollection(); - LegendItemCollection old = plot.getFixedLegendItems(); - - Color color = theme.parseLineColorField(); - if (color == null) { - color = Color.BLACK; - } - - Color textColor = theme.parseTextColor(); - if (textColor == null) { - textColor = Color.BLACK; - } - - LegendItem newItem = new LegendItem(fa.getLabel(), color); - LegendSection ls = (settings != null ? - settings.getLegendSection() : null); - newItem.setLabelFont (new Font( - DEFAULT_FONT_NAME, - Font.PLAIN, - ls != null ? ls.getFontSize() : null) - ); - - newItem.setLabelPaint(textColor); - - lic.add(newItem); - // (Re-)Add prior legend entries. - if (old != null) { - old.addAll(lic); - } - else { - old = lic; - } - plot.setFixedLegendItems(old); - } - } - - // The 'Sticky' Annotations (at axis, with line and text). - for (StickyAxisAnnotation sta: fa.getAxisTextAnnotations()) { - addStickyAnnotation( - sta, plot, area, lineStyle, textStyle, theme, - datasets.get(new Integer(sta.getAxisSymbol()))); - } - - // Other Text Annotations (e.g. labels of (manual) points). - for (XYTextAnnotation ta: fa.getTextAnnotations()) { - // Style the text. - if (textStyle != null) { - textStyle.apply(ta); - } - ta.setY(area.above(0.05d, ta.getY())); - plot.getRenderer().addAnnotation( - ta, org.jfree.ui.Layer.FOREGROUND); - } - } - } - - /** - * Add a text and a line annotation. - * @param area convenience to determine positions in plot. - * @param theme (optional) theme document - */ - public static void addStickyAnnotation( - StickyAxisAnnotation annotation, - XYPlot plot, - ChartArea area, - LineStyle lineStyle, - TextStyle textStyle, - ThemeDocument theme, - AxisDataset dataset - ) { - // OPTIMIZE pre-calculate area-related values - final float TEXT_OFF = 0.03f; - - XYLineAnnotation lineAnnotation = null; - XYTextAnnotation textAnnotation = null; - - int axisIndex = annotation.getAxisSymbol(); - XYItemRenderer renderer = null; - if (dataset != null && dataset.getDatasets().length > 0) { - renderer = plot.getRendererForDataset(dataset.getDatasets()[0]); - } - else { - renderer = plot.getRenderer(); - } - - if (annotation.atX()) { - textAnnotation = new CollisionFreeXYTextAnnotation( - annotation.getText(), - annotation.getPos(), - area.ofGround(TEXT_OFF)); - // OPTIMIZE externalize the calculation involving PI. - //textAnnotation.setRotationAngle(270f*Math.PI/180f); - lineAnnotation = createGroundStickAnnotation( - area, annotation.getPos(), lineStyle); - textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT); - textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT); - } - else { - // Stick to the "right" (opposed to left) Y-Axis. - if (axisIndex != 0 && plot.getRangeAxis(axisIndex) != null) { - // OPTIMIZE: Pass a different area to this function, - // do the adding to renderer outside (let this - // function return the annotations). - // Note that this path is travelled rarely. - textAnnotation = new CollisionFreeXYTextAnnotation( - annotation.getText(), - area.ofRight(TEXT_OFF), - annotation.getPos() - ); - textAnnotation.setRotationAnchor(TextAnchor.CENTER_RIGHT); - textAnnotation.setTextAnchor(TextAnchor.CENTER_RIGHT); - lineAnnotation = createRightStickAnnotation( - area, annotation.getPos(), lineStyle); - - // hit-lines for duration curve - ChartArea area2 = new ChartArea( - plot.getDomainAxis(), plot.getRangeAxis(axisIndex)); - if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { - // New line annotation to hit curve. - if (theme.parseShowVerticalLine()) { - XYLineAnnotation hitLineAnnotation = - createStickyLineAnnotation( - StickyAxisAnnotation.SimpleAxis.X_AXIS, - annotation.getHitPoint(), annotation.getPos(), - // annotation.getHitPoint(), - area2, lineStyle); - renderer.addAnnotation(hitLineAnnotation, - org.jfree.ui.Layer.BACKGROUND); - } - if (theme.parseShowHorizontalLine()) { - XYLineAnnotation lineBackAnnotation = - createStickyLineAnnotation( - StickyAxisAnnotation.SimpleAxis.Y_AXIS2, - annotation.getPos(), annotation.getHitPoint(), - area2, lineStyle); - renderer.addAnnotation(lineBackAnnotation, - org.jfree.ui.Layer.BACKGROUND); - } - } - } - else { // Stick to the left y-axis. - textAnnotation = new CollisionFreeXYTextAnnotation( - annotation.getText(), - area.ofLeft(TEXT_OFF), - annotation.getPos()); - textAnnotation.setRotationAnchor(TextAnchor.CENTER_LEFT); - textAnnotation.setTextAnchor(TextAnchor.CENTER_LEFT); - lineAnnotation = createLeftStickAnnotation( - area, annotation.getPos(), lineStyle); - if (!Float.isNaN(annotation.getHitPoint()) && theme != null) { - // New line annotation to hit curve. - if (theme.parseShowHorizontalLine()) { - XYLineAnnotation hitLineAnnotation = - createStickyLineAnnotation( - StickyAxisAnnotation.SimpleAxis.Y_AXIS, - annotation.getPos(), annotation.getHitPoint(), - area, lineStyle); - renderer.addAnnotation(hitLineAnnotation, - org.jfree.ui.Layer.BACKGROUND); - } - if (theme.parseShowVerticalLine()) { - XYLineAnnotation lineBackAnnotation = - createStickyLineAnnotation( - StickyAxisAnnotation.SimpleAxis.X_AXIS, - annotation.getHitPoint(), annotation.getPos(), - area, lineStyle); - renderer.addAnnotation(lineBackAnnotation, - org.jfree.ui.Layer.BACKGROUND); - } - } - } - } - - // Style the text. - if (textStyle != null) { - textStyle.apply(textAnnotation); - } - - // Add the Annotations to renderer. - renderer.addAnnotation(textAnnotation, org.jfree.ui.Layer.FOREGROUND); - renderer.addAnnotation(lineAnnotation, org.jfree.ui.Layer.FOREGROUND); - } - - /** - * Create annotation that sticks to "ground" (X) axis. - * @param area helper to calculate coordinates - * @param pos one-dimensional position (distance from axis) - * @param lineStyle the line style to use for the line. - */ - public static XYLineAnnotation createGroundStickAnnotation( - ChartArea area, float pos, LineStyle lineStyle - ) { - // Style the line. - if (lineStyle != null) { - return new XYLineAnnotation( - pos, area.atGround(), - pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET), - new BasicStroke(lineStyle.getWidth()),lineStyle.getColor()); - } - else { - return new XYLineAnnotation( - pos, area.atGround(), - pos, area.ofGround(ANNOTATIONS_AXIS_OFFSET)); - } - } - - - /** - * Create annotation that sticks to the second Y axis ("right"). - * @param area helper to calculate coordinates - * @param pos one-dimensional position (distance from axis) - * @param lineStyle the line style to use for the line. - */ - public static XYLineAnnotation createRightStickAnnotation( - ChartArea area, float pos, LineStyle lineStyle - ) { - // Style the line. - if (lineStyle != null) { - return new XYLineAnnotation( - area.atRight(), pos, - area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos, - new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); - } - else { - return new XYLineAnnotation( - area.atRight(), pos, - area.ofRight(ANNOTATIONS_AXIS_OFFSET), pos); - } - } - /** - * Create annotation that sticks to the first Y axis ("left"). - * @param area helper to calculate coordinates - * @param pos one-dimensional position (distance from axis) - * @param lineStyle the line style to use for the line. - */ - public static XYLineAnnotation createLeftStickAnnotation( - ChartArea area, float pos, LineStyle lineStyle - ) { - // Style the line. - if (lineStyle != null) { - return new XYLineAnnotation( - area.atLeft(), pos, - area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos, - new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); - } - else { - return new XYLineAnnotation( - area.atLeft(), pos, - area.ofLeft(ANNOTATIONS_AXIS_OFFSET), pos); - } - } - - - /** - * Create a line from a axis to a given point. - * @param axis The "simple" axis. - * @param fromD1 from-location in first dimension. - * @param toD2 to-location in second dimension. - * @param area helper to calculate offsets. - * @param lineStyle optional line style. - */ - public static XYLineAnnotation createStickyLineAnnotation( - StickyAxisAnnotation.SimpleAxis axis, float fromD1, float toD2, - ChartArea area, LineStyle lineStyle - ) { - double anchorX1 = 0d, anchorX2 = 0d, anchorY1 = 0d, anchorY2 = 0d; - switch(axis) { - case X_AXIS: - anchorX1 = fromD1; - anchorX2 = fromD1; - anchorY1 = area.atGround(); - anchorY2 = toD2; - break; - case Y_AXIS: - anchorX1 = area.atLeft(); - anchorX2 = toD2; - anchorY1 = fromD1; - anchorY2 = fromD1; - break; - case Y_AXIS2: - anchorX1 = area.atRight(); - anchorX2 = toD2; - anchorY1 = fromD1; - anchorY2 = fromD1; - break; - } - // Style the line. - if (lineStyle != null) { - return new XYLineAnnotation( - anchorX1, anchorY1, - anchorX2, anchorY2, - new BasicStroke(lineStyle.getWidth()), lineStyle.getColor()); - } - else { - return new XYLineAnnotation( - anchorX1, anchorY1, - anchorX2, anchorY2); - } - } - -};