Mercurial > dive4elements > river
changeset 9555:ef5754ba5573
Implemented legend aggregation based on type of themes.
Added theme-editor style configuration for aggregated legend entries.
Only configured themes get aggregated.
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContext.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContext.java Tue Oct 23 16:26:48 2018 +0200 @@ -49,6 +49,9 @@ "flys.export.facetfilter"; /** The key that is used to store the map of themes in the context. */ + public static final String LEGEND = "flys.legend.map"; + + /** The key that is used to store the map of themes in the context. */ public static final String THEMES = "flys.themes.map"; @@ -67,7 +70,6 @@ /** Key to store the configured modules in the context. */ public static final String MODULES = "flys.modules"; - /** * The default constructor. */
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContextFactory.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContextFactory.java Tue Oct 23 16:26:48 2018 +0200 @@ -9,8 +9,8 @@ package org.dive4elements.river.artifacts.context; import java.io.File; - import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -18,39 +18,28 @@ import javax.xml.xpath.XPathConstants; import org.apache.log4j.Logger; - import org.dive4elements.artifactdatabase.state.State; import org.dive4elements.artifactdatabase.state.StateEngine; - import org.dive4elements.artifactdatabase.transition.Transition; import org.dive4elements.artifactdatabase.transition.TransitionEngine; - import org.dive4elements.artifacts.ArtifactContextFactory; +import org.dive4elements.artifacts.ContextInjector; import org.dive4elements.artifacts.GlobalContext; - -import org.dive4elements.artifacts.ContextInjector; - import org.dive4elements.artifacts.common.utils.Config; import org.dive4elements.artifacts.common.utils.ElementConverter; import org.dive4elements.artifacts.common.utils.XMLUtils; - import org.dive4elements.river.artifacts.model.Module; import org.dive4elements.river.artifacts.model.RiverFactory; import org.dive4elements.river.artifacts.model.ZoomScale; - import org.dive4elements.river.artifacts.states.StateFactory; - import org.dive4elements.river.artifacts.transitions.TransitionFactory; - import org.dive4elements.river.exports.GeneratorLookup; import org.dive4elements.river.exports.OutGenerator; - import org.dive4elements.river.model.River; import org.dive4elements.river.themes.Theme; import org.dive4elements.river.themes.ThemeFactory; import org.dive4elements.river.themes.ThemeGroup; import org.dive4elements.river.themes.ThemeMapping; - import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -68,69 +57,60 @@ private static Logger log = Logger.getLogger(RiverContextFactory.class); /** The XPath to the artifacts configured in the configuration. */ - public static final String XPATH_ARTIFACTS = - "/artifact-database/artifacts/artifact"; + private static final String XPATH_ARTIFACTS = "/artifact-database/artifacts/artifact"; /** The XPath to the name of the artifact. */ - public static final String XPATH_ARTIFACT_NAME = "/artifact/@name"; + private static final String XPATH_ARTIFACT_NAME = "/artifact/@name"; /** The XPath to the xlink ref in an artifact configuration. */ - public static final String XPATH_XLINK = "xlink:href"; + private static final String XPATH_XLINK = "xlink:href"; /** The XPath to the transitions configured in the artifact config. */ - public static final String XPATH_TRANSITIONS = - "/artifact/states/transition"; + private static final String XPATH_TRANSITIONS = "/artifact/states/transition"; /** The XPath to the states configured in the artifact config. */ - public static final String XPATH_STATES = - "/artifact/states/state"; - - public static final String XPATH_OUTPUT_GENERATORS = - "/artifact-database/output-generators//output-generator"; - - public static final String XPATH_THEME_CONFIG = - "/artifact-database/flys/themes/configuration/text()"; - - public static final String XPATH_THEMES = - "theme"; + private static final String XPATH_STATES = "/artifact/states/state"; - public static final String XPATH_THEME_GROUPS = - "/themes/themegroup"; - - public static final String XPATH_THEME_MAPPINGS = - "/themes/mappings/mapping"; + private static final String XPATH_OUTPUT_GENERATORS = "/artifact-database/output-generators//output-generator"; - public static final String XPATH_RIVER_WMS = - "/artifact-database/floodmap/river"; + private static final String XPATH_THEME_CONFIG = "/artifact-database/flys/themes/configuration/text()"; - public static final String XPATH_MODULES = - "/artifact-database/modules/module"; + private static final String XPATH_THEMES = "theme"; - private static final String XPATH_ZOOM_SCALES = - "/artifact-database/options/zoom-scales/zoom-scale"; + private static final String XPATH_LEGEND_GROUP = "/themes/legendgroup"; - private static final String XPATH_DGM_PATH = - "/artifact-database/options/dgm-path/text()"; + private static final String XPATH_THEME_GROUPS = "/themes/themegroup"; + + private static final String XPATH_THEME_MAPPINGS = "/themes/mappings/mapping"; + + private static final String XPATH_RIVER_WMS = "/artifact-database/floodmap/river"; + + private static final String XPATH_MODULES = "/artifact-database/modules/module"; + + private static final String XPATH_ZOOM_SCALES = "/artifact-database/options/zoom-scales/zoom-scale"; + + private static final String XPATH_DGM_PATH = "/artifact-database/options/dgm-path/text()"; private static GlobalContext GLOBAL_CONTEXT_INSTANCE; - /** * Creates a new D4EArtifactContext object and initialize all * components required by the application. * - * @param config The artifact server configuration. + * @param config + * The artifact server configuration. * @return a D4EArtifactContext. */ @Override - public GlobalContext createArtifactContext(Document config) { - RiverContext context = new RiverContext(config); + public GlobalContext createArtifactContext(final Document config) { + final RiverContext context = new RiverContext(config); configureTransitions(config, context); configureStates(config, context); configureOutGenerators(config, context); configureThemes(config, context); configureThemesMappings(config, context); + configureLegend(config, context); configureFloodmapWMS(config, context); configureModules(config, context); configureZoomScales(config, context); @@ -147,25 +127,17 @@ return GLOBAL_CONTEXT_INSTANCE; } - - private void configureDGMPath(Document config, RiverContext context) { - String dgmPath = (String) XMLUtils.xpath( - config, - XPATH_DGM_PATH, - XPathConstants.STRING); + private void configureDGMPath(final Document config, final RiverContext context) { + final String dgmPath = (String) XMLUtils.xpath(config, XPATH_DGM_PATH, XPathConstants.STRING); context.put("dgm-path", dgmPath); } - - protected void configureZoomScales(Document config, RiverContext context) { - NodeList list = (NodeList)XMLUtils.xpath( - config, - XPATH_ZOOM_SCALES, - XPathConstants.NODESET); - ZoomScale scale = new ZoomScale(); + private void configureZoomScales(final Document config, final RiverContext context) { + final NodeList list = (NodeList) XMLUtils.xpath(config, XPATH_ZOOM_SCALES, XPathConstants.NODESET); + final ZoomScale scale = new ZoomScale(); for (int i = 0; i < list.getLength(); i++) { - Element element = (Element)list.item(i); + final Element element = (Element) list.item(i); String river = "default"; double range = 0d; double radius = 10d; @@ -174,72 +146,63 @@ } if (!element.hasAttribute("range")) { continue; - } - else { - String r = element.getAttribute("range"); + } else { + final String r = element.getAttribute("range"); try { range = Double.parseDouble(r); } - catch (NumberFormatException nfe) { + catch (final NumberFormatException nfe) { continue; } } if (!element.hasAttribute("radius")) { continue; - } - else { - String r = element.getAttribute("radius"); + } else { + final String r = element.getAttribute("radius"); try { radius = Double.parseDouble(r); } - catch (NumberFormatException nfe) { + catch (final NumberFormatException nfe) { continue; } } scale.addRange(river, range, radius); - } - context.put("zoomscale", scale); + } + context.put("zoomscale", scale); } - /** * This method initializes the transition configuration. * - * @param config the config document. - * @param context the RiverContext. + * @param config + * the config document. + * @param context + * the RiverContext. */ - protected void configureTransitions( - Document config, - RiverContext context - ) { - TransitionEngine engine = new TransitionEngine(); + private void configureTransitions(final Document config, final RiverContext context) { + final TransitionEngine engine = new TransitionEngine(); - List<Document> artifacts = getArtifactConfigurations(config); + final List<Document> artifacts = getArtifactConfigurations(config); log.info("Found " + artifacts.size() + " artifacts in the config."); - for (Document doc: artifacts) { + for (final Document doc : artifacts) { - String artName = (String) XMLUtils.xpath( - doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); + final String artName = (String) XMLUtils.xpath(doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); - NodeList list = (NodeList) XMLUtils.xpath( - doc, XPATH_TRANSITIONS, XPathConstants.NODESET); + final NodeList list = (NodeList) XMLUtils.xpath(doc, XPATH_TRANSITIONS, XPathConstants.NODESET); if (list == null) { - log.warn("The artifact " + artName + - " has no transitions configured."); + log.warn("The artifact " + artName + " has no transitions configured."); continue; } - int trans = list.getLength(); + final int trans = list.getLength(); - log.info( - "Artifact '" + artName + "' has " + trans + " transitions."); + log.info("Artifact '" + artName + "' has " + trans + " transitions."); for (int i = 0; i < trans; i++) { - Transition t = TransitionFactory.createTransition( - list.item(i)); - String s = t.getFrom(); + final Transition t = TransitionFactory.createTransition(list.item(i)); + final String s = t.getFrom(); engine.addTransition(s, t); } } @@ -247,87 +210,82 @@ context.put(RiverContext.TRANSITION_ENGINE_KEY, engine); } - /** * This method returns all artifact documents defined in - * <code>config</code>. <br>NOTE: The artifact configurations need to be + * <code>config</code>. <br> + * NOTE: The artifact configurations need to be * stored in own files referenced by an xlink. * - * @param config The global configuration. + * @param config + * The global configuration. * * @return an array of Artifact configurations. */ - protected List<Document> getArtifactConfigurations(Document config) { - NodeList artifacts = (NodeList) XMLUtils.xpath( - config, XPATH_ARTIFACTS, XPathConstants.NODESET); + private List<Document> getArtifactConfigurations(final Document config) { + final NodeList artifacts = (NodeList) XMLUtils.xpath(config, XPATH_ARTIFACTS, XPathConstants.NODESET); - int count = artifacts.getLength(); + final int count = artifacts.getLength(); - ArrayList<Document> docs = new ArrayList<Document>(count); + final ArrayList<Document> docs = new ArrayList<>(count); for (int i = 0; i < count; i++) { - Element tmp = (Element) artifacts.item(i); + final Element tmp = (Element) artifacts.item(i); String xlink = tmp.getAttribute(XPATH_XLINK); - xlink = Config.replaceConfigDir(xlink); + xlink = Config.replaceConfigDir(xlink); if (!xlink.isEmpty()) { - File file = new File(xlink); + final File file = new File(xlink); if (!file.isFile() || !file.canRead()) { - log.warn("Artifact configuration '" - + file + "' not found."); + log.warn("Artifact configuration '" + file + "' not found."); } else { - Document doc = XMLUtils.parseDocument(file); + final Document doc = XMLUtils.parseDocument(file); if (doc != null) { docs.add(doc); } } continue; } - Document doc = XMLUtils.newDocument(); - Node copy = doc.adoptNode(tmp.cloneNode(true)); + final Document doc = XMLUtils.newDocument(); + final Node copy = doc.adoptNode(tmp.cloneNode(true)); doc.appendChild(copy); docs.add(doc); } return docs; } - /** * This method initializes the transition configuration. * - * @param config the config document. - * @param context the RiverContext. + * @param config + * the config document. + * @param context + * the RiverContext. */ - protected void configureStates(Document config, RiverContext context) { - StateEngine engine = new StateEngine(); + private void configureStates(final Document config, final RiverContext context) { + final StateEngine engine = new StateEngine(); - List<Document> artifacts = getArtifactConfigurations(config); + final List<Document> artifacts = getArtifactConfigurations(config); log.info("Found " + artifacts.size() + " artifacts in the config."); - for (Document doc: artifacts) { - List<State> states = new ArrayList<State>(); + for (final Document doc : artifacts) { + final List<State> states = new ArrayList<>(); - String artName = (String) XMLUtils.xpath( - doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); + final String artName = (String) XMLUtils.xpath(doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); - NodeList stateList = (NodeList) XMLUtils.xpath( - doc, XPATH_STATES, XPathConstants.NODESET); + final NodeList stateList = (NodeList) XMLUtils.xpath(doc, XPATH_STATES, XPathConstants.NODESET); if (stateList == null) { - log.warn("The artifact " + artName + - " has no states configured."); + log.warn("The artifact " + artName + " has no states configured."); continue; } - int count = stateList.getLength(); + final int count = stateList.getLength(); - log.info( - "Artifact '" + artName + "' has " + count + " states."); + log.info("Artifact '" + artName + "' has " + count + " states."); for (int i = 0; i < count; i++) { - states.add(StateFactory.createState( - stateList.item(i))); + states.add(StateFactory.createState(stateList.item(i))); } engine.addStates(artName, states); @@ -336,23 +294,18 @@ context.put(RiverContext.STATE_ENGINE_KEY, engine); } - /** * This method intializes the provided output generators. * - * @param config the config document. - * @param context the RiverContext. + * @param config + * the config document. + * @param context + * the RiverContext. */ - protected void configureOutGenerators( - Document config, - RiverContext context - ) { - NodeList outGenerators = (NodeList) XMLUtils.xpath( - config, - XPATH_OUTPUT_GENERATORS, - XPathConstants.NODESET); + private void configureOutGenerators(final Document config, final RiverContext context) { + final NodeList outGenerators = (NodeList) XMLUtils.xpath(config, XPATH_OUTPUT_GENERATORS, XPathConstants.NODESET); - int num = outGenerators == null ? 0 : outGenerators.getLength(); + final int num = outGenerators == null ? 0 : outGenerators.getLength(); if (num == 0) { log.warn("No output generators configured in this application."); @@ -361,17 +314,17 @@ log.info("Found " + num + " configured output generators."); - GeneratorLookup generators = new GeneratorLookup(); + final GeneratorLookup generators = new GeneratorLookup(); int idx = 0; for (int i = 0; i < num; i++) { - Element item = (Element)outGenerators.item(i); + final Element item = (Element) outGenerators.item(i); - String names = item.getAttribute("names").trim(); - String clazz = item.getAttribute("class").trim(); - String converter = item.getAttribute("converter").trim(); - String injectors = item.getAttribute("injectors").trim(); + final String names = item.getAttribute("names").trim(); + final String clazz = item.getAttribute("class").trim(); + final String converter = item.getAttribute("converter").trim(); + final String injectors = item.getAttribute("injectors").trim(); if (names.isEmpty() || clazz.isEmpty()) { continue; @@ -380,9 +333,9 @@ Class<OutGenerator> generatorClass = null; try { - generatorClass = (Class<OutGenerator>)Class.forName(clazz); + generatorClass = (Class<OutGenerator>) Class.forName(clazz); } - catch (ClassNotFoundException cnfe) { + catch (final ClassNotFoundException cnfe) { log.error(cnfe, cnfe); continue; } @@ -391,18 +344,16 @@ if (!converter.isEmpty()) { try { - ElementConverter ec = - (ElementConverter)Class.forName(converter) - .newInstance(); + final ElementConverter ec = (ElementConverter) Class.forName(converter).newInstance(); cfg = ec.convert(item); } - catch (ClassNotFoundException cnfe) { + catch (final ClassNotFoundException cnfe) { log.error(cnfe, cnfe); } - catch (InstantiationException ie) { + catch (final InstantiationException ie) { log.error(ie); } - catch (IllegalAccessException iae) { + catch (final IllegalAccessException iae) { log.error(iae); } } @@ -410,28 +361,26 @@ List<ContextInjector> cis = null; if (!injectors.isEmpty()) { - cis = new ArrayList<ContextInjector>(); - for (String injector: injectors.split("[\\s,]+")) { + cis = new ArrayList<>(); + for (final String injector : injectors.split("[\\s,]+")) { try { - ContextInjector ci = (ContextInjector)Class - .forName(injector) - .newInstance(); + final ContextInjector ci = (ContextInjector) Class.forName(injector).newInstance(); ci.setup(item); cis.add(ci); } - catch (ClassNotFoundException cnfe) { + catch (final ClassNotFoundException cnfe) { log.error(cnfe, cnfe); } - catch (InstantiationException ie) { + catch (final InstantiationException ie) { log.error(ie); } - catch (IllegalAccessException iae) { + catch (final IllegalAccessException iae) { log.error(iae); } } } - for (String key: names.split("[\\s,]+")) { + for (String key : names.split("[\\s,]+")) { if (!(key = key.trim()).isEmpty()) { generators.putGenerator(key, generatorClass, cfg, cis); idx++; @@ -444,23 +393,23 @@ context.put(RiverContext.FACETFILTER_KEY, generators); } - /** * This methods reads the configured themes and puts them into the * RiverContext. * - * @param config The global configuration. - * @param context The RiverContext. + * @param config + * The global configuration. + * @param context + * The RiverContext. */ - protected void configureThemes(Document config, RiverContext context) { + private void configureThemes(final Document config, final RiverContext context) { log.debug("RiverContextFactory.configureThemes"); - Document cfg = getThemeConfig(config); + final Document cfg = getThemeConfig(config); - NodeList themeGroups = (NodeList) XMLUtils.xpath( - cfg, XPATH_THEME_GROUPS, XPathConstants.NODESET); + final NodeList themeGroups = (NodeList) XMLUtils.xpath(cfg, XPATH_THEME_GROUPS, XPathConstants.NODESET); - int groupNum = themeGroups != null ? themeGroups.getLength() : 0; + final int groupNum = themeGroups != null ? themeGroups.getLength() : 0; if (groupNum == 0) { log.warn("There are no theme groups configured!"); @@ -468,105 +417,126 @@ log.info("Found " + groupNum + " theme groups in configuration"); - List<ThemeGroup> groups = new ArrayList<ThemeGroup>(); + final List<ThemeGroup> groups = new ArrayList<>(); for (int g = 0; g < groupNum; g++) { - Element themeGroup = (Element) themeGroups.item(g); - NodeList themes = (NodeList) XMLUtils.xpath( - themeGroup, XPATH_THEMES, XPathConstants.NODESET); + final Element themeGroup = (Element) themeGroups.item(g); - int num = themes != null ? themes.getLength() : 0; + final Map<String, Theme> theThemes = readThemes(cfg, themeGroup); - if (num == 0) { + if (theThemes.size() == 0) { log.warn("There are no themes configured!"); return; } - log.info("Theme group has " + num + " themes."); - - Map<String, Theme> theThemes = new HashMap<String, Theme>(); - - for (int i = 0; i < num; i++) { - Node theme = themes.item(i); - - Theme theTheme = ThemeFactory.createTheme(cfg, theme); - - if (theme != null) { - theThemes.put(theTheme.getName(), theTheme); - } - } - String gName = themeGroup.getAttribute("name"); + final String gName = themeGroup.getAttribute("name"); groups.add(new ThemeGroup(gName, theThemes)); - log.info( - "Initialized " + theThemes.size() + "/" + num + " themes " + - "of theme-group '" + gName + "'"); + log.info("Initialized " + theThemes.size() + "/" + theThemes.size() + " themes " + "of theme-group '" + gName + "'"); } context.put(RiverContext.THEMES, groups); } /** + * This methods reads the configured themes and puts them into the + * RiverContext. + * + * @param config + * The global configuration. + * @param context + * The RiverContext. + */ + private void configureLegend(final Document config, final RiverContext context) { + log.debug("RiverContextFactory.configureLegend"); + + final Map<String, Theme> legendGroup = readLegend(config); + context.put(RiverContext.LEGEND, legendGroup); + } + + private Map<String, Theme> readLegend(final Document config) { + + final Document cfg = getThemeConfig(config); + + final Node legendGroup = (Node) XMLUtils.xpath(cfg, XPATH_LEGEND_GROUP, XPathConstants.NODE); + if (legendGroup == null) { + log.warn("There is no legend group configured"); + return Collections.emptyMap(); + } + + return readThemes(cfg, legendGroup); + } + + private Map<String, Theme> readThemes(final Document cfg, final Node themeGroup) { + final NodeList themes = (NodeList) XMLUtils.xpath(themeGroup, XPATH_THEMES, XPathConstants.NODESET); + if (themes == null) + return Collections.emptyMap(); + + final int num = themes.getLength(); + log.info("Theme group has " + num + " themes."); + final Map<String, Theme> theThemes = new HashMap<>(); + + for (int i = 0; i < num; i++) { + final Node theme = themes.item(i); + + final Theme theTheme = ThemeFactory.createTheme(cfg, theme); + theThemes.put(theTheme.getName(), theTheme); + } + + return theThemes; + } + + /** * This method is used to retrieve the theme configuration document. * - * @param config The global configuration. + * @param config + * The global configuration. * * @return the theme configuration. */ - protected Document getThemeConfig(Document config) { - String themeConfig = (String) XMLUtils.xpath( - config, - XPATH_THEME_CONFIG, - XPathConstants.STRING); + private Document getThemeConfig(final Document config) { + String themeConfig = (String) XMLUtils.xpath(config, XPATH_THEME_CONFIG, XPathConstants.STRING); themeConfig = Config.replaceConfigDir(themeConfig); log.debug("Parse theme cfg: " + themeConfig); - return XMLUtils.parseDocument( - new File(themeConfig), true, XMLUtils.CONF_RESOLVER); + return XMLUtils.parseDocument(new File(themeConfig), true, XMLUtils.CONF_RESOLVER); } - - protected void configureThemesMappings( - Document cfg, - RiverContext context - ) { + private void configureThemesMappings(final Document cfg, final RiverContext context) { log.debug("RiverContextFactory.configureThemesMappings"); - Document config = getThemeConfig(cfg); + final Document config = getThemeConfig(cfg); - NodeList mappings = (NodeList) XMLUtils.xpath( - config, XPATH_THEME_MAPPINGS, XPathConstants.NODESET); + final NodeList mappings = (NodeList) XMLUtils.xpath(config, XPATH_THEME_MAPPINGS, XPathConstants.NODESET); - int num = mappings != null ? mappings.getLength() : 0; + final int num = mappings != null ? mappings.getLength() : 0; if (num == 0) { log.warn("No theme <--> facet mappins found!"); return; } - Map<String, List<ThemeMapping>> mapping = - new HashMap<String, List<ThemeMapping>>(); + final Map<String, List<ThemeMapping>> mapping = new HashMap<>(); for (int i = 0; i < num; i++) { - Element node = (Element)mappings.item(i); + final Element node = (Element) mappings.item(i); - String from = node.getAttribute("from"); - String to = node.getAttribute("to"); - String pattern = node.getAttribute("pattern"); - String masterAttrPattern = node.getAttribute("masterAttr"); - String outputPattern = node.getAttribute("output"); + final String from = node.getAttribute("from"); + final String to = node.getAttribute("to"); + final String pattern = node.getAttribute("pattern"); + final String masterAttrPattern = node.getAttribute("masterAttr"); + final String outputPattern = node.getAttribute("output"); if (from.length() > 0 && to.length() > 0) { List<ThemeMapping> tm = mapping.get(from); if (tm == null) { - tm = new ArrayList<ThemeMapping>(); + tm = new ArrayList<>(); mapping.put(from, tm); } - tm.add(new ThemeMapping( - from, to, pattern, masterAttrPattern, outputPattern)); + tm.add(new ThemeMapping(from, to, pattern, masterAttrPattern, outputPattern)); } } @@ -575,26 +545,25 @@ context.put(RiverContext.THEME_MAPPING, mapping); } - /** * Reads configured floodmap river WMSs from floodmap.xml and * loads them into the given RiverContext. + * * @param cfg * @param context */ - protected void configureFloodmapWMS(Document cfg, RiverContext context) { - Map<String, String> riverWMS = new HashMap<String, String>(); + private void configureFloodmapWMS(final Document cfg, final RiverContext context) { + final Map<String, String> riverWMS = new HashMap<>(); - NodeList rivers = (NodeList) XMLUtils.xpath( - cfg, XPATH_RIVER_WMS, XPathConstants.NODESET); + final NodeList rivers = (NodeList) XMLUtils.xpath(cfg, XPATH_RIVER_WMS, XPathConstants.NODESET); - int num = rivers != null ? rivers.getLength() : 0; + final int num = rivers != null ? rivers.getLength() : 0; for (int i = 0; i < num; i++) { - Element e = (Element) rivers.item(i); + final Element e = (Element) rivers.item(i); - String river = e.getAttribute("name"); - String url = XMLUtils.xpathString(e, "river-wms/@url", null); + final String river = e.getAttribute("name"); + final String url = XMLUtils.xpathString(e, "river-wms/@url", null); if (river != null && url != null) { riverWMS.put(river, url); @@ -606,16 +575,16 @@ context.put(RiverContext.RIVER_WMS, riverWMS); } - /** * This method initializes the modules configuration. * - * @param config the config document. - * @param context the RiverContext. + * @param config + * the config document. + * @param context + * the RiverContext. */ - protected void configureModules(Document cfg, RiverContext context) { - NodeList modulenodes = (NodeList) XMLUtils.xpath( - cfg, XPATH_MODULES, XPathConstants.NODESET); + private void configureModules(final Document cfg, final RiverContext context) { + final NodeList modulenodes = (NodeList) XMLUtils.xpath(cfg, XPATH_MODULES, XPathConstants.NODESET); final int num = modulenodes != null ? modulenodes.getLength() : 0; @@ -627,24 +596,23 @@ final String attrselected = e.getAttribute("selected"); final boolean selected = Boolean.parseBoolean(attrselected); final String group = e.getAttribute("group"); - + log.debug("Loaded module " + modulename); - + final NodeList children = e.getChildNodes(); final List<String> rivers = new ArrayList<>(children.getLength()); for (int j = 0; j < children.getLength(); j++) { if (children.item(j).getNodeType() != Node.ELEMENT_NODE) { continue; } - - final Element ce = (Element)children.item(j); + + final Element ce = (Element) children.item(j); if (ce.hasAttribute("uuid")) { rivers.add(ce.getAttribute("uuid")); - } - else if (ce.hasAttribute("name")) { + } else if (ce.hasAttribute("name")) { final List<River> allRivers = RiverFactory.getRivers(); final String name = ce.getAttribute("name"); - for (final River r: allRivers) { + for (final River r : allRivers) { if (name.equals(r.getName())) { rivers.add(r.getModelUuid()); break; @@ -656,5 +624,4 @@ } context.put(RiverContext.MODULES, modules); } -} -// 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/AbstractChartGenerator.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/AbstractChartGenerator.java Tue Oct 23 16:26:48 2018 +0200 @@ -58,7 +58,6 @@ import org.dive4elements.river.themes.ThemeDocument; 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; @@ -96,6 +95,8 @@ private static final String DEFAULT_CHART_FORMAT = "png"; + private static final int DEFAULT_LEGEND_AGGREGATION_THRESHOLD = 10; + private static final String XPATH_CHART_EXPORT = "/art:action/art:attributes/art:export/@art:value"; private static final String XPATH_CHART_SIZE = "/art:action/art:attributes/art:size"; @@ -224,15 +225,6 @@ 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 @@ -340,7 +332,7 @@ final LegendSection legendSection = new LegendSection(); legendSection.setVisibility(isLegendVisible()); legendSection.setFontSize(getLegendFontSize()); - legendSection.setAggregationThreshold(10); + legendSection.setAggregationThreshold(DEFAULT_LEGEND_AGGREGATION_THRESHOLD); return legendSection; } @@ -686,46 +678,25 @@ 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; + protected final LegendAggregator createLegendBuilder() { + return new LegendAggregator(getLegendAggregationThreshold(), createLegendLabelFont()); } - /** - * Create new legend entries, dependent on settings. - * - * @param plot - * The plot for which to modify the legend. - */ - protected final void aggregateLegendEntries(final XYPlot plot) { + private int getLegendAggregationThreshold() { final ChartSettings chartSettings = getChartSettings(); if (chartSettings == null) - return; + return DEFAULT_LEGEND_AGGREGATION_THRESHOLD; - final Integer threshold = chartSettings.getLegendSection().getAggregationThreshold(); + final LegendSection legendSection = chartSettings.getLegendSection(); + if (legendSection == null) + return DEFAULT_LEGEND_AGGREGATION_THRESHOLD; - final int aggrThreshold = threshold != null ? threshold.intValue() : 0; + final Integer threshold = legendSection.getAggregationThreshold(); + if (threshold == null) + return DEFAULT_LEGEND_AGGREGATION_THRESHOLD; - LegendProcessor.aggregateLegendEntries(plot, aggrThreshold); + return threshold; } /** @@ -818,7 +789,7 @@ * @param plot * plot to add datasets to. */ - protected void addDatasets(final XYPlot plot) { + protected void addDatasets(final XYPlot plot, final LegendAggregator legendBuilder) { log.debug("addDatasets()"); // AxisDatasets are sorted, but some might be empty. @@ -846,7 +817,7 @@ plot.setDataset(datasetIndex, dataset); plot.mapDatasetToRangeAxis(datasetIndex, axisIndex); - applyThemes(plot, dataset, datasetIndex); + applyThemes(plot, legendBuilder, dataset, datasetIndex); datasetIndex++; } @@ -855,7 +826,6 @@ } } - axisDataset.setPlotAxisIndex(axisIndex); axisIndex++; } } @@ -875,14 +845,12 @@ * true if the series describes an area and shall be rendered * as such. */ - private void applyThemes(final XYPlot plot, final XYDataset dataset, final int datasetIndex) { - - final Font legendFont = createLegendLabelFont(); + private void applyThemes(final XYPlot plot, final LegendAggregator legendBuilder, final XYDataset dataset, final int datasetIndex) { if (dataset instanceof StyledXYDataset) - ((StyledXYDataset) dataset).applyTheme(this.context.getMeta(), plot, datasetIndex, legendFont); + ((StyledXYDataset) dataset).applyTheme(this.context.getMeta(), plot, legendBuilder, datasetIndex); else - applyLineTheme(plot, dataset, datasetIndex, legendFont); + applyLineTheme(plot, legendBuilder, dataset, datasetIndex); } /** @@ -933,12 +901,9 @@ * The index of the renderer / dataset. * @param legendFont2 */ - private void applyLineTheme(final XYPlot plot, final XYDataset dataset, final int idx, final Font legendFont) { + private void applyLineTheme(final XYPlot plot, final LegendAggregator legendBuilder, 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 XYLineAndShapeRenderer renderer = createRenderer(plot, idx); for (int s = 0, num = dataset.getSeriesCount(); s < num; s++) { @@ -952,29 +917,24 @@ // 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); - } + // if (series.getItemCount() == 1) { + // renderer.setSeriesShapesVisible(s, true); + // } LegendItem legendItem = renderer.getLegendItem(idx, s); if (legendItem.getLabel().endsWith(" ")) { legendItem = null; } + final String themeType = series instanceof StyledSeries ? ((StyledSeries) series).getThemeType() : null; + if (legendItem != null) { - legendItem.setLabelFont(legendFont); - lic.add(legendItem); + legendBuilder.addLegendItem(themeType, 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); } @@ -1077,7 +1037,7 @@ AxisDataset axisDataset = this.datasets.get(idx); if (axisDataset == null) { - axisDataset = createAxisDataset(idx); + axisDataset = new AxisDataset(); this.datasets.put(idx, axisDataset); } @@ -1321,12 +1281,12 @@ return true; } - protected final void addAnnotationsToRenderer(final XYPlot plot) { + protected final void addAnnotationsToRenderer(final XYPlot plot, final LegendAggregator legendBuilder) { - final AnnotationRenderer annotationRenderer = new AnnotationRenderer(getChartSettings(), this.datasets, DEFAULT_FONT_NAME); - annotationRenderer.addAnnotationsToRenderer(plot, this.annotations); + final AnnotationRenderer annotationRenderer = new AnnotationRenderer(this.datasets); + annotationRenderer.addAnnotationsToRenderer(plot, legendBuilder, this.annotations); - doAddFurtherAnnotations(plot, this.annotations); + doAddFurtherAnnotations(plot, legendBuilder, this.annotations); } /** @@ -1334,7 +1294,7 @@ * * Does nothing by default. */ - protected void doAddFurtherAnnotations(final XYPlot plot, final List<RiverAnnotation> annotations) { + protected void doAddFurtherAnnotations(final XYPlot plot, final LegendAggregator legendBuilder, final List<RiverAnnotation> annotations) { } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/AnnotationRenderer.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/AnnotationRenderer.java Tue Oct 23 16:26:48 2018 +0200 @@ -11,7 +11,6 @@ import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Font; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -26,7 +25,6 @@ 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; @@ -42,16 +40,10 @@ 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; + public AnnotationRenderer(final Map<Integer, AxisDataset> datasets) { this.datasets = datasets; - this.fontName = fontName; } /** @@ -66,7 +58,7 @@ * @param datasets * Map of axis index and datasets */ - public final void addAnnotationsToRenderer(final XYPlot plot, final List<RiverAnnotation> annotations) { + public final void addAnnotationsToRenderer(final XYPlot plot, final LegendAggregator legendBuilder, final List<RiverAnnotation> annotations) { if (annotations == null || annotations.isEmpty()) { log.debug("addAnnotationsToRenderer: no annotations."); return; @@ -88,10 +80,6 @@ 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; @@ -104,22 +92,12 @@ 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); + // REMARK: connection to facet is lost at this point + final String themeType = null; + + legendBuilder.addLegendItem(themeType, newItem); } } @@ -231,7 +209,8 @@ renderer.addAnnotation(lineAnnotation, org.jfree.ui.Layer.FOREGROUND); } - public final void addYAnnotationsToRenderer(final XYPlot plot, final SortedMap<Integer, RiverAnnotation> yAnnotations) { + public final void addYAnnotationsToRenderer(final XYPlot plot, final LegendAggregator legendBuilder, + final SortedMap<Integer, RiverAnnotation> yAnnotations) { final List<RiverAnnotation> annotations = new ArrayList<>(); for (final Map.Entry<Integer, RiverAnnotation> entry : yAnnotations.entrySet()) { @@ -249,7 +228,7 @@ } } - addAnnotationsToRenderer(plot, annotations); + addAnnotationsToRenderer(plot, legendBuilder, annotations); } /**
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator2.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator2.java Tue Oct 23 16:26:48 2018 +0200 @@ -298,8 +298,8 @@ 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); + protected final void addYAnnotationsToRenderer(final XYPlot plot, LegendAggregator legendBuilder) { + final AnnotationRenderer annotationRenderer = new AnnotationRenderer(getDatasets()); + annotationRenderer.addYAnnotationsToRenderer(plot, legendBuilder, this.yAnnotations); } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/CrossSectionGenerator.java Tue Oct 23 16:26:48 2018 +0200 @@ -33,13 +33,12 @@ import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.Formatter; import org.dive4elements.river.utils.RiverUtils; -import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.LegendItem; import org.jfree.chart.annotations.XYBoxAnnotation; import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYSeries; - /** * An OutGenerator that generates cross section graphs. */ @@ -165,7 +164,7 @@ } @Override - protected void doAddFurtherAnnotations(XYPlot plot, List<RiverAnnotation> annotations) { + protected void doAddFurtherAnnotations(XYPlot plot, LegendAggregator legendBuilder, List<RiverAnnotation> annotations) { // Paints for the boxes/lines. Stroke basicStroke = new BasicStroke(1.0f); @@ -189,17 +188,14 @@ if (theme != null) { textStyle = theme.parseComplexTextStyle(); if (fa.getLabel() != null) { - LegendItemCollection lic = new LegendItemCollection(); - LegendItemCollection old = plot.getFixedLegendItems(); - lic.add(createLegendItem(theme, fa.getLabel())); - // (Re-)Add prior legend entries. - if (old != null) { - old.addAll(lic); - } - else { - old = lic; - } - plot.setFixedLegendItems(old); + + Color color = theme.parseLineColorField(); + if (color == null) + color = Color.BLACK; + + final String themeType = null; + + legendBuilder.addLegendItem(themeType, new LegendItem(fa.getLabel(), color)); } } @@ -282,17 +278,20 @@ CallContext context = getContext(); + final String facetDescription = artifactFacet.getFacetDescription(); + final String facetName = artifactFacet.getFacetName(); + if (name.equals(CROSS_SECTION)) { - doCrossSectionOut( + doCrossSectionOut(facetName, artifactFacet.getData(context), - artifactFacet.getFacetDescription(), + facetDescription, attr, visible); } else if (name.endsWith(CROSS_SECTION_WATER_LINE)) { - doCrossSectionWaterLineOut( + doCrossSectionWaterLineOut(facetName, artifactFacet.getData(context), - artifactFacet.getFacetDescription(), + facetDescription, attr, visible); } @@ -304,7 +303,7 @@ } else if (name.equals(HYK)) { doHyk(artifactFacet.getData(context), - artifactFacet.getFacetDescription(), + facetDescription, attr, visible); } @@ -312,9 +311,9 @@ VegetationZonesCrossSectionProcessor.generateSeries(this, artifactFacet, context, attr, visible); } else if (FacetTypes.IS.MANUALLINE(name)) { - doCrossSectionWaterLineOut( + doCrossSectionWaterLineOut(facetName, artifactFacet.getData(context), - artifactFacet.getFacetDescription(), + facetDescription, attr, visible); } @@ -345,6 +344,7 @@ * @param theme Theme for the data series. */ protected void doCrossSectionWaterLineOut( + String facetName, Object o, String seriesName, ThemeDocument theme, @@ -354,7 +354,7 @@ Lines.LineData lines = (Lines.LineData) o; // DO NOT SORT DATA! This destroys the gaps indicated by NaNs. - StyledXYSeries series = new StyledXYSeries(seriesName, false, theme); + StyledXYSeries series = new StyledXYSeries(facetName, seriesName, false, theme); CallContext context = getContext(); @@ -433,7 +433,8 @@ * @param seriesName name of the data (line) to display in legend. * @param theme Theme for the data series. */ - protected void doCrossSectionOut( + private void doCrossSectionOut( + String facetName, Object o, String seriesName, ThemeDocument theme, @@ -441,7 +442,7 @@ ) { log.debug("CrossSectionGenerator.doCrossSectionOut"); - XYSeries series = new StyledXYSeries(seriesName, theme); + XYSeries series = new StyledXYSeries(facetName, seriesName, theme); StyledSeriesBuilder.addPoints(series, (double [][]) o, false);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/DiagramGenerator.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DiagramGenerator.java Tue Oct 23 16:26:48 2018 +0200 @@ -170,8 +170,9 @@ adjustPlot(plot); //debugAxis(plot); + final LegendAggregator legendBuilder = createLegendBuilder(); - addDatasets(plot); + addDatasets(plot, legendBuilder); //debugDatasets(plot); @@ -199,13 +200,13 @@ //debugAxis(plot); // These have to go after the autozoom. - addAnnotationsToRenderer(plot); - addYAnnotationsToRenderer(plot); + addAnnotationsToRenderer(plot, legendBuilder); + addYAnnotationsToRenderer(plot, legendBuilder); // Add a logo (maybe). addLogo(plot); - aggregateLegendEntries(plot); + legendBuilder.apply( context, plot ); /* allow extenders to do some work */ final Collection<ChartExtender> extenders = this.diagramAttributes.getExtenders(); @@ -383,14 +384,6 @@ return ((XYSeriesCollection) dataset).getSeries(idx); } - - @Override - protected AxisDataset createAxisDataset(int idx) { - log.debug("Create new AxisDataset for index: " + idx); - return new AxisDataset(idx); - } - - /** * Put debug output about datasets. */ @@ -961,50 +954,11 @@ ((NumberAxis) rangeAxis).setNumberFormatOverride(nf); } - - /** - * Create a hash from a legenditem. - * This hash can then be used to merge legend items labels. - * @return hash for given legenditem to identify mergeables. - */ - public static String legendItemHash(LegendItem li) { - // TODO Do proper implementation. - // Ensure that only mergable sets are created. - // getFillPaint() - // getFillPaintTransformer() - // getLabel() - // getLine() - // getLinePaint() - // getLineStroke() - // getOutlinePaint() - // getOutlineStroke() - // Shape getShape() - // String getToolTipText() - // String getURLText() - // boolean isLineVisible() - // boolean isShapeFilled() - // boolean isShapeOutlineVisible() - // boolean isShapeVisible() - String hash = li.getLinePaint().toString(); - String label = li.getLabel(); - if (label.startsWith("W (") || label.startsWith("W(")) { - hash += "-W-"; - } - else if (label.startsWith("Q(") || label.startsWith("Q (")) { - hash += "-Q-"; - } - - // WQ.java holds example of using regex Matcher/Pattern. - - return hash; - } - /** True if x axis has been inverted. */ public boolean isInverted() { return inverted; } - /** Set to true if x axis should be inverted. * This can not be set to false afterwards. */ public void setInverted(boolean value) {
--- a/artifacts/src/main/java/org/dive4elements/river/exports/DischargeGenerator.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/DischargeGenerator.java Tue Oct 23 16:26:48 2018 +0200 @@ -10,7 +10,6 @@ import java.awt.Font; import org.apache.log4j.Logger; -import org.dive4elements.river.artifacts.resources.Resources; import org.dive4elements.river.exports.injector.InjectorConstants; import org.dive4elements.river.jfree.AxisDataset; import org.dive4elements.river.jfree.DoubleBounds; @@ -36,8 +35,8 @@ } @Override - public void addDatasets(XYPlot plot) { - super.addDatasets(plot); + public void addDatasets(XYPlot plot, final LegendAggregator legendBuilder) { + super.addDatasets(plot, legendBuilder); Object pnp = getContext().getContextValue(PNP); if (!(pnp instanceof Number)) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/LegendAggregator.java Tue Oct 23 16:26:48 2018 +0200 @@ -0,0 +1,228 @@ +/** 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.Font; +import java.awt.Paint; +import java.awt.Shape; +import java.awt.Stroke; +import java.util.AbstractMap.SimpleEntry; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.dive4elements.artifacts.CallContext; +import org.dive4elements.river.artifacts.context.RiverContext; +import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.jfree.StyledSeries; +import org.dive4elements.river.jfree.StyledXYDataset; +import org.dive4elements.river.themes.Theme; +import org.dive4elements.river.themes.ThemeDocument; +import org.dive4elements.river.themes.ThemeFactory; +import org.jfree.chart.LegendItem; +import org.jfree.chart.LegendItemCollection; +import org.jfree.chart.plot.XYPlot; +import org.jfree.data.general.Dataset; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; +import org.w3c.dom.Document; + +/** + * Builds and adds legend entries to the plot. + * + * @author Gernot Belger + */ +public class LegendAggregator { + + private static final String NULL_THEME_TYPE = ""; //$NON-NLS-1$ + + private static final String I10N_MERGED = "legend.aggregator.merged"; //$NON-NLS-1$ + + private final List<Map.Entry<LegendItem, String>> legendItems = new ArrayList<>(); + + private final Map<String, List<LegendItem>> itemsPerThemeType = new HashMap<>(); + + private final Font labelFont; + + private final int aggregationThreshold; + + public LegendAggregator(final int aggregationThreshold, final Font labelFont) { + this.aggregationThreshold = aggregationThreshold; + this.labelFont = labelFont; + } + + public void addLegendItem(final String themeType, final LegendItem item) { + + item.setLabelFont(this.labelFont); + + this.legendItems.add(new SimpleEntry<>(item, themeType)); + + final List<LegendItem> perThemeType = getItemsPerThemeType(themeType); + perThemeType.add(item); + } + + private List<LegendItem> getItemsPerThemeType(final String themeType) { + + final String key = themeType == null ? NULL_THEME_TYPE : themeType; + + if (!this.itemsPerThemeType.containsKey(key)) + this.itemsPerThemeType.put(key, new ArrayList<LegendItem>()); + + return this.itemsPerThemeType.get(key); + } + + /** + * Apply the gathered items to the plot. Use only once. + */ + public void apply(final CallContext context, final XYPlot plot) { + + final LegendItemCollection aggregatedItems = new LegendItemCollection(); + + /* marker set for types that are already aggregated */ + final Set<String> aggregatedTypes = new HashSet<>(); + + for (final Entry<LegendItem, String> entry : this.legendItems) { + + final LegendItem item = entry.getKey(); + final String themeType = entry.getValue(); + + /* ignore already aggregated items */ + if (aggregatedTypes.contains(themeType)) + continue; + + /* aggregate known types if count over threshold */ + final Theme legendTheme = getLegendTheme(context, themeType); + + if (legendTheme != null && getItemsPerThemeType(themeType).size() > this.aggregationThreshold) { + + final String labelDescription = Resources.getMsg(context.getMeta(), legendTheme.getDescription()); + final String labelMerged = Resources.getMsg(context.getMeta(), I10N_MERGED); + final String label = String.format("%s (%s)", labelDescription, labelMerged); + + final List<LegendItem> items = findDistinctItems(getItemsPerThemeType(themeType)); + /* add items for each distinct shape, only the last one gets the label */ + for (final Iterator<LegendItem> iterator = items.iterator(); iterator.hasNext();) { + + final LegendItem legendItem = iterator.next(); + final String itemLabel = iterator.hasNext() ? "," : label; + + /* create and add aggregated item(s) */ + final LegendItem aggregatedItem = createAggregatedItem(legendItem, legendTheme, itemLabel); + aggregatedItems.add(aggregatedItem); + } + + /* mark as handles */ + aggregatedTypes.add(themeType); + + } else { + /* simply add normal items */ + aggregatedItems.add(item); + } + } + + plot.setFixedLegendItems(aggregatedItems); + + this.itemsPerThemeType.clear(); + this.legendItems.clear(); + } + + /** + * Extract distinct items, curently only those that are different regarding their shape + */ + private List<LegendItem> findDistinctItems(final List<LegendItem> items) { + + // HACKY: we hash by unique shape, because we know that the used shapes are cashed in a static cache. + final Map<Shape, LegendItem> shapeMap = new IdentityHashMap<>(); + + for (final LegendItem item : items) { + + final Shape shape = item.isShapeVisible() ? item.getShape() : null; + if (!shapeMap.containsKey(shape)) + shapeMap.put(shape, item); + } + + return new ArrayList<>(shapeMap.values()); + } + + private LegendItem createAggregatedItem(final LegendItem item, final Theme legendTheme, final String label) { + /* clone properties from current item */ + final String description = item.getDescription(); + final String tooltipText = item.getToolTipText(); + final String urlText = item.getURLText(); + final boolean shapeVisible = item.isShapeVisible(); + final Shape shape = item.getShape(); + final boolean shapeFilled = item.isShapeFilled(); + final Paint fillPaint = item.getFillPaint(); + final boolean shapeOutlineVisible = item.isShapeOutlineVisible(); + final Paint outlinePaint = item.getOutlinePaint(); + final Stroke outlineStroke = item.getOutlineStroke(); + final boolean lineVisible = item.isLineVisible(); + final Shape line = item.getLine(); + final Stroke lineStroke = item.getLineStroke(); + final Paint linePaint = item.getLinePaint(); + final LegendItem aggregatedItem = new LegendItem(label, description, tooltipText, urlText, shapeVisible, shape, shapeFilled, fillPaint, + shapeOutlineVisible, outlinePaint, outlineStroke, lineVisible, line, lineStroke, linePaint); + + aggregatedItem.setDataset(item.getDataset()); + aggregatedItem.setDatasetIndex(item.getDatasetIndex()); + aggregatedItem.setFillPaintTransformer(item.getFillPaintTransformer()); + aggregatedItem.setLabelFont(item.getLabelFont()); + aggregatedItem.setLabelPaint(item.getLabelPaint()); + aggregatedItem.setSeriesIndex(item.getSeriesIndex()); + + /* let styled dataset apply specific theme configuration */ + applyThemeToLegend(aggregatedItem, legendTheme); + + return aggregatedItem; + } + + private void applyThemeToLegend(final LegendItem item, final Theme legendTheme) { + + final Dataset dataset = item.getDataset(); + if (dataset == null) + return; + + final Document xml = legendTheme.toXML(); + final ThemeDocument themeDocument = new ThemeDocument(xml); + + if (dataset instanceof StyledXYDataset) { + final StyledXYDataset styledDataset = (StyledXYDataset) dataset; + styledDataset.applyAggregatedLegendTheme(item, themeDocument); + return; + } + + if (dataset instanceof XYSeriesCollection) { + + final int seriesIndex = item.getSeriesIndex(); + + final XYSeriesCollection seriesCollection = (XYSeriesCollection) dataset; + if (seriesIndex >= 0 && seriesIndex < seriesCollection.getSeriesCount()) { + final XYSeries series = seriesCollection.getSeries(seriesIndex); + + if (series instanceof StyledSeries) { + ((StyledSeries) series).applyAggregatedLegendTheme(item, themeDocument); + } + } + } + } + + private Theme getLegendTheme(final CallContext context, final String themeType) { + + final RiverContext flysContext = context instanceof RiverContext ? (RiverContext) context : (RiverContext) context.globalContext(); + + return ThemeFactory.getLegendTheme(flysContext, themeType); + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/exports/LegendProcessor.java Mon Oct 22 18:26:05 2018 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,153 +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.exports; - -import java.awt.geom.Line2D; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; - -import org.jfree.chart.LegendItem; -import org.jfree.chart.LegendItemCollection; -import org.jfree.chart.plot.XYPlot; - -/** Class to process Plots legends. */ -public abstract class LegendProcessor { - - /** (Empty) shape for aggregated Legend Items. */ - private static final Line2D.Double SPACE = new Line2D.Double(0, 0, 0, 0); - - /** Prevent instantiations. */ - private LegendProcessor() { - } - - /** - * Create a hash from a legenditem. - * This hash can then be used to merge legend items labels. - * - * @return hash for given legenditem to identify mergeables. - */ - protected static String legendItemHash(final LegendItem li) { - // TODO Do proper implementation. - // Ensure that only mergable sets are created. - // getFillPaint() - // getFillPaintTransformer() - // getLabel() - // getLine() - // getLinePaint() - // getLineStroke() - // getOutminePaint() - // getOutlineStroke() - // Shape getShape() - // String getToolTipText() - // String getURLText() - // boolean isLineVisible() - // boolean isShapeFilled() - // boolean isShapeOutlineVisible() - // boolean isShapeVisible() - final String hash = li.getLinePaint().toString(); - // XXX: DEAD CODE // String label = li.getLabel(); - /* - * if (label.startsWith("W (") || label.startsWith("W(")) { - * hash += "-W-"; - * } - * else if (label.startsWith("Q(") || label.startsWith("Q (")) { - * hash += "-Q-"; - * } - */ - - // WQ.java holds example of using regex Matcher/Pattern. - - return hash; - } - - /** - * Create new legend entries, dependent on settings. - * - * @param plot - * The plot for which to modify the legend. - * @param threshold - * How many items are needed for aggregation to - * be triggered? - */ - public static void aggregateLegendEntries(final XYPlot plot, final int threshold) { - final LegendItemCollection old = plot.getLegendItems(); - // Find "similar" entries if aggregation is enabled. - - int maxListSize = 0; - final int AGGR_THRESHOLD = threshold; - - if (AGGR_THRESHOLD > old.getItemCount() || AGGR_THRESHOLD <= 0) { - return; - } - - final HashMap<String, List<LegendItem>> entries = new LinkedHashMap<>(); - // for (Iterator<LegendItem> i = old.iterator(); i.hasNext();) { - - final Iterator<LegendItem> iterator = old.iterator(); - while (iterator.hasNext()) { - final LegendItem item = iterator.next(); - final String hash = legendItemHash(item); - List<LegendItem> itemList = entries.get(hash); - if (itemList == null) { - itemList = new ArrayList<>(); - entries.put(hash, itemList); - } - itemList.add(item); - - if (itemList.size() > maxListSize) { - maxListSize = itemList.size(); - } - } - - if (maxListSize < AGGR_THRESHOLD) { - // No need to do anything. - return; - } - - // Run over collected entries, merge their names and create new - // entry if needed. - final LegendItemCollection newLegend = new LegendItemCollection(); - for (final List<LegendItem> itemList : entries.values()) { - if (itemList.size() >= AGGR_THRESHOLD) { - // Now do merging. - // XXX: DEAD CODE // LegendItem item = itemList.get(0); - // Unfortunately we cannot clone and just setDescription, - // as this method was added in JFreeChart 1.0.14 - // (we are at .13). - - // Remove the shapes of all but the first items, - // to prevent "overfill" of legenditemblock. - for (int i = 0, I = itemList.size(); i < I; i++) { - if (i != 0) { - final LegendItem litem = itemList.get(i); - - // Make shape and line really small. - final LegendItem merged = new LegendItem("," + litem.getLabel(), litem.getDescription(), litem.getToolTipText(), litem.getURLText(), - false, SPACE, false, litem.getFillPaint(), false, litem.getOutlinePaint(), litem.getOutlineStroke(), false, SPACE, - litem.getLineStroke(), litem.getLinePaint()); - newLegend.add(merged); - } else { - newLegend.add(itemList.get(i)); - } - } - } else { - // Do not merge entries. - for (final LegendItem li : itemList) { - newLegend.add(li); - } - } - } - - plot.setFixedLegendItems(newLegend); - } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/artifacts/src/main/java/org/dive4elements/river/exports/TimeseriesChartGenerator.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/TimeseriesChartGenerator.java Tue Oct 23 16:26:48 2018 +0200 @@ -17,7 +17,6 @@ import org.dive4elements.river.jfree.RiverAnnotation; import org.dive4elements.river.jfree.StyledTimeSeries; import org.dive4elements.river.jfree.TimeBounds; -import org.dive4elements.river.jfree.AxisDataset; import org.dive4elements.river.themes.ThemeDocument; import java.awt.Color; @@ -27,7 +26,6 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; @@ -36,15 +34,12 @@ import org.apache.log4j.Logger; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; -import org.jfree.chart.LegendItem; -import org.jfree.chart.LegendItemCollection; import org.jfree.chart.annotations.XYAnnotation; import org.jfree.chart.annotations.XYImageAnnotation; import org.jfree.chart.annotations.XYTextAnnotation; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.plot.Marker; import org.jfree.chart.plot.XYPlot; -import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; import org.jfree.data.Range; import org.jfree.data.general.Series; import org.jfree.data.time.FixedMillisecond; @@ -84,10 +79,10 @@ public TimeseriesChartGenerator() { super(); - xBounds = new HashMap<Integer, Bounds>(); - yBounds = new HashMap<Integer, Bounds>(); - domainMarker = new ArrayList<Marker>(); - valueMarker = new ArrayList<Marker>(); + xBounds = new HashMap<>(); + yBounds = new HashMap<>(); + domainMarker = new ArrayList<>(); + valueMarker = new ArrayList<>(); } @Override @@ -111,7 +106,11 @@ plot.setBackgroundPaint(Color.WHITE); adjustPlot(plot); - addDatasets(plot); + + final LegendAggregator legendBuilder = createLegendBuilder(); + + addDatasets(plot, legendBuilder); + adjustAxes(plot); addDomainAxisMarker(plot); addValueAxisMarker(plot); @@ -119,14 +118,15 @@ consumeAxisSettings(plot); - addAnnotationsToRenderer(plot); + addAnnotationsToRenderer(plot, legendBuilder); + legendBuilder.apply(context, plot); + addLogo(plot); - aggregateLegendEntries(plot); + return chart; } - /** * Return left most data points x value (on first axis). * Shortcut, especially to be overridden in (LS) charts where @@ -321,19 +321,6 @@ return ((TimeSeriesCollection) dataset).getSeries(idx); } - - /** - * This method creates new instances of AxisDataset. - * - * @param idx The symbol for the new AxisDataset. - */ - @Override - protected AxisDataset createAxisDataset(int idx) { - log.debug("Create a new AxisDataset for index: " + idx); - return new AxisDataset(idx); - } - - @Override protected void combineXBounds(Bounds bounds, int index) { if (bounds != null) { @@ -634,13 +621,14 @@ boolean visible, int axisIndex ) { + final String facetName = aandf.getFacetName(); String seriesName = aandf.getFacetDescription(); - TimeSeries series = new StyledTimeSeries(seriesName, theme); + + TimeSeries series = new StyledTimeSeries(facetName, seriesName, theme); // Add text annotations for single points. - List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>(); - HashMap<FixedMillisecond, String> names = - new HashMap<FixedMillisecond, String>(); + List<XYTextAnnotation> xy = new ArrayList<>(); + HashMap<FixedMillisecond, String> names = new HashMap<>(); try { JSONArray points = new JSONArray((String) o);
--- a/artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/exports/XYChartGenerator.java Tue Oct 23 16:26:48 2018 +0200 @@ -36,6 +36,7 @@ import org.jfree.data.xy.XYDataset; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; +import org.jfree.ui.RectangleInsets; import org.json.JSONArray; import org.json.JSONException; @@ -77,9 +78,9 @@ /** The log that is used in this generator. */ private static Logger log = Logger.getLogger(XYChartGenerator.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; @@ -93,8 +94,8 @@ public XYChartGenerator() { super(); - xBounds = new HashMap<Integer, Bounds>(); - yBounds = new HashMap<Integer, Bounds>(); + xBounds = new HashMap<>(); + yBounds = new HashMap<>(); } @@ -127,7 +128,9 @@ //debugAxis(plot); - addDatasets(plot); + final LegendAggregator legendBuilder = createLegendBuilder(); + + addDatasets(plot, legendBuilder); //debugDatasets(plot); @@ -151,13 +154,14 @@ //debugAxis(plot); + // These have to go after the autozoom. - addAnnotationsToRenderer(plot); + addAnnotationsToRenderer(plot, legendBuilder); // Add a logo (maybe). addLogo(plot); - aggregateLegendEntries(plot); + legendBuilder.apply(context, plot); return chart; } @@ -315,14 +319,6 @@ return ((XYSeriesCollection) dataset).getSeries(idx); } - - @Override - protected AxisDataset createAxisDataset(int idx) { - log.debug("Create new AxisDataset for index: " + idx); - return new AxisDataset(idx); - } - - /** * Put debug output about datasets. */ @@ -911,7 +907,7 @@ int axisIndex ) { String seriesName = aandf.getFacetDescription(); - XYSeries series = new StyledXYSeries(seriesName, theme); + XYSeries series = new StyledXYSeries(aandf.getFacetName(), seriesName, theme); // Add text annotations for single points. List<XYTextAnnotation> xy = new ArrayList<XYTextAnnotation>(); @@ -946,44 +942,6 @@ addAxisSeries(series, axisIndex, visible); } - - /** - * Create a hash from a legenditem. - * This hash can then be used to merge legend items labels. - * @return hash for given legenditem to identify mergeables. - */ - public static String legendItemHash(LegendItem li) { - // TODO Do proper implementation. - // Ensure that only mergable sets are created. - // getFillPaint() - // getFillPaintTransformer() - // getLabel() - // getLine() - // getLinePaint() - // getLineStroke() - // getOutlinePaint() - // getOutlineStroke() - // Shape getShape() - // String getToolTipText() - // String getURLText() - // boolean isLineVisible() - // boolean isShapeFilled() - // boolean isShapeOutlineVisible() - // boolean isShapeVisible() - String hash = li.getLinePaint().toString(); - String label = li.getLabel(); - if (label.startsWith("W (") || label.startsWith("W(")) { - hash += "-W-"; - } - else if (label.startsWith("Q(") || label.startsWith("Q (")) { - hash += "-Q-"; - } - - // WQ.java holds example of using regex Matcher/Pattern. - - return hash; - } - /** True if x axis has been inverted. */ public boolean isInverted() { return inverted;
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/AxisDataset.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/AxisDataset.java Tue Oct 23 16:26:48 2018 +0200 @@ -21,25 +21,13 @@ */ public class AxisDataset { - /** Symbolic integer, but also coding the priority (0 goes first). */ - protected int axisSymbol; - /** List of assigned datasets (in order). */ - protected List<XYDataset> datasets; + private final List<XYDataset> datasets = new ArrayList<>(); /** Range to use to include all given datasets. */ - protected Range range; - - /** Index of axis in plot. */ - protected int plotAxisIndex; + private Range range; - protected boolean rangeDirty; - - /** Create AxisDataset. */ - public AxisDataset(final int symb) { - this.axisSymbol = symb; - this.datasets = new ArrayList<>(); - } + private boolean rangeDirty; /** Add a dataset to internal list for this axis. */ public void addDataset(final XYDataset dataset) { @@ -99,14 +87,4 @@ public boolean isEmpty() { return this.datasets.isEmpty(); } - - /** Set the 'real' axis index that this axis is mapped to. */ - public void setPlotAxisIndex(final int axisIndex) { - this.plotAxisIndex = axisIndex; - } - - /** Get the 'real' axis index that this axis is mapped to. */ - public int getPlotAxisIndex() { - return this.plotAxisIndex; - } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StripedAreaDataset.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StripedAreaDataset.java Tue Oct 23 16:26:48 2018 +0200 @@ -10,15 +10,15 @@ package org.dive4elements.river.jfree; import java.awt.Color; -import java.awt.Font; import java.util.ArrayList; import java.util.List; +import org.dive4elements.artifactdatabase.state.Facet; import org.dive4elements.artifacts.CallMeta; +import org.dive4elements.river.exports.LegendAggregator; import org.dive4elements.river.java2d.ShapeUtils; import org.dive4elements.river.themes.ThemeDocument; import org.jfree.chart.LegendItem; -import org.jfree.chart.LegendItemCollection; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYSeries; import org.jfree.data.xy.XYSeriesCollection; @@ -67,9 +67,16 @@ private final List<Stripe> stripes = new ArrayList<>(); + /** + * A 'type' that allows to categorize themes by it. Tyically this is simply the facet-name of the originating + * {@link Facet}. + */ + private final String themeType; + private final ThemeDocument theme; - public StripedAreaDataset(final ThemeDocument theme) { + public StripedAreaDataset(final String themeType, final ThemeDocument theme) { + this.themeType = themeType; this.theme = theme; } @@ -93,28 +100,18 @@ } @Override - public void applyTheme(final CallMeta callMeta, final XYPlot plot, final int datasetIndex, final Font legendFont) { + public void applyTheme(final CallMeta callMeta, final XYPlot plot, final LegendAggregator legendBuilder, final int datasetIndex) { final StripedAreaDatasetRenderer renderer = createRenderer(); plot.setRenderer(datasetIndex, renderer); - final LegendItemCollection newItems = new LegendItemCollection(); - final LegendItemCollection oldItems = plot.getFixedLegendItems(); - final int seriesCount = getSeriesCount(); for (int i = 0; i < seriesCount; i++) { final LegendItem legendItem = renderer.getLegendItem(datasetIndex, i); - if (legendItem != null) { - legendItem.setLabelFont(legendFont); - newItems.add(legendItem); - } + if (legendItem != null) + legendBuilder.addLegendItem(this.themeType, legendItem); } - - if (oldItems != null) - newItems.addAll(oldItems); - - plot.setFixedLegendItems(newItems); } private StripedAreaDatasetRenderer createRenderer() { @@ -130,4 +127,9 @@ return renderer; } + + @Override + public void applyAggregatedLegendTheme(final LegendItem item, final ThemeDocument legendTheme) { + /* not implemented at the moment */ + } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/Style.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/Style.java Tue Oct 23 16:26:48 2018 +0200 @@ -8,6 +8,8 @@ package org.dive4elements.river.jfree; +import org.dive4elements.river.themes.ThemeDocument; +import org.jfree.chart.LegendItem; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; @@ -19,5 +21,6 @@ XYLineAndShapeRenderer applyTheme(XYLineAndShapeRenderer r, int idx); XYLineAndShapeRenderer getRenderer(); -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : + + void applyAggregatedLegendTheme(LegendItem item, ThemeDocument theme); +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java Tue Oct 23 16:26:48 2018 +0200 @@ -10,7 +10,6 @@ import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Font; import java.awt.Paint; import java.awt.Stroke; import java.awt.TexturePaint; @@ -19,13 +18,14 @@ import java.awt.image.BufferedImage; import org.apache.log4j.Logger; +import org.dive4elements.artifactdatabase.state.Facet; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.exports.LegendAggregator; import org.dive4elements.river.java2d.ShapeUtils; import org.dive4elements.river.themes.ThemeDocument; import org.dive4elements.river.utils.Formatter; import org.jfree.chart.LegendItem; -import org.jfree.chart.LegendItemCollection; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYSeriesCollection; @@ -55,14 +55,26 @@ private final ThemeDocument theme; /** + * A 'type' that allows to categorize themes by it. Tyically this is simply the facet-name of the originating + * {@link Facet}. + */ + private final String themeType; + + /** * @param theme * the theme-document. + * @param string */ - public StyledAreaSeriesCollection(final ThemeDocument theme) { + public StyledAreaSeriesCollection(final String themeType, final ThemeDocument theme) { + this.themeType = themeType; this.theme = theme; this.mode = FILL_MODE.BETWEEN; } + public String getThemeType() { + return this.themeType; + } + /** Gets the Fill mode. */ private FILL_MODE getMode() { return this.mode; @@ -74,10 +86,7 @@ } @Override - public void applyTheme(final CallMeta callMeta, final XYPlot plot, final int datasetIndex, final Font legendFont) { - - final LegendItemCollection lic = new LegendItemCollection(); - final LegendItemCollection anno = plot.getFixedLegendItems(); + public void applyTheme(final CallMeta callMeta, final XYPlot plot, final LegendAggregator legendBuilder, final int datasetIndex) { log.debug("Registering an 'area'renderer at idx: " + datasetIndex); @@ -98,17 +107,10 @@ final LegendItem legendItem = dRenderer.getLegendItem(datasetIndex, 0); if (legendItem != null) { - legendItem.setLabelFont(legendFont); - lic.add(legendItem); + legendBuilder.addLegendItem(this.themeType, legendItem); } else { - log.warn("Could not get LegentItem for renderer: " + datasetIndex + ", series-idx " + 0); + log.warn("Could not get LegengItem for renderer: " + datasetIndex + ", series-idx " + 0); } - - if (anno != null) { - lic.addAll(anno); - } - - plot.setFixedLegendItems(lic); } /** @@ -274,5 +276,9 @@ public boolean shouldCalculateRange() { return this.theme.parseCalculateRange(); } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : + + @Override + public void applyAggregatedLegendTheme(final LegendItem item, final ThemeDocument legendTheme) { + /* not implemented */ + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledSeries.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledSeries.java Tue Oct 23 16:26:48 2018 +0200 @@ -8,14 +8,17 @@ package org.dive4elements.river.jfree; +import org.dive4elements.river.themes.ThemeDocument; +import org.jfree.chart.LegendItem; /** * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> */ public interface StyledSeries { - void setStyle(Style style); + String getThemeType(); Style getStyle(); -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : + + void applyAggregatedLegendTheme(LegendItem item, ThemeDocument theme); +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledTimeSeries.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledTimeSeries.java Tue Oct 23 16:26:48 2018 +0200 @@ -11,7 +11,7 @@ import java.awt.Shape; import org.dive4elements.river.themes.ThemeDocument; - +import org.jfree.chart.LegendItem; import org.jfree.data.time.TimeSeries; /** @@ -19,25 +19,35 @@ */ public class StyledTimeSeries extends TimeSeries implements StyledSeries { - private Style style; + private static final long serialVersionUID = 1L; - public StyledTimeSeries(String key, ThemeDocument theme) { + private final Style style; + + private final String themeType; + + public StyledTimeSeries(final String themeType, final String key, final ThemeDocument theme) { + this(themeType, key, theme, null); + } + + public StyledTimeSeries(final String themeType, final String key, final ThemeDocument theme, final Shape shape) { super(key); - setStyle(new XYStyle(theme)); - } - - public StyledTimeSeries(String key, ThemeDocument theme, Shape shape) { - super(key); - setStyle(new XYStyle(theme, shape)); + + this.style = new XYStyle(theme, shape); + this.themeType = themeType; } @Override - public void setStyle(Style style) { - this.style = style; + public String getThemeType() { + return this.themeType; } @Override public Style getStyle() { - return style; + return this.style; + } + + @Override + public void applyAggregatedLegendTheme(final LegendItem item, final ThemeDocument theme) { + this.style.applyAggregatedLegendTheme(item, theme); } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYDataset.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYDataset.java Tue Oct 23 16:26:48 2018 +0200 @@ -9,16 +9,18 @@ */ package org.dive4elements.river.jfree; -import java.awt.Font; - import org.dive4elements.artifacts.CallMeta; +import org.dive4elements.river.exports.LegendAggregator; +import org.dive4elements.river.themes.ThemeDocument; +import org.jfree.chart.LegendItem; import org.jfree.chart.plot.XYPlot; import org.jfree.data.xy.XYDataset; /** * @author Domenico Nardi Tironi - * */ public interface StyledXYDataset extends XYDataset { - void applyTheme(CallMeta callMeta, XYPlot plot, int datasetIndex, Font legendFont); + void applyTheme(CallMeta callMeta, XYPlot plot, LegendAggregator legendBuilder, int datasetIndex); + + void applyAggregatedLegendTheme(LegendItem item, ThemeDocument theme); } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYSeries.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledXYSeries.java Tue Oct 23 16:26:48 2018 +0200 @@ -8,170 +8,129 @@ package org.dive4elements.river.jfree; -import java.util.List; +import java.awt.Shape; import java.util.Map; -import org.apache.log4j.Logger; - -import org.dive4elements.river.model.River; - +import org.dive4elements.artifactdatabase.state.Facet; import org.dive4elements.artifacts.Artifact; import org.dive4elements.artifacts.CallContext; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.access.RiverAccess; import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.model.River; import org.dive4elements.river.themes.ThemeDocument; - -import org.jfree.data.xy.XYDataItem; +import org.jfree.chart.LegendItem; import org.jfree.data.xy.XYSeries; -import java.awt.Shape; - /** * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> */ -public class StyledXYSeries -extends XYSeries -implements StyledSeries, HasLabel, XYMetaDataset { +public class StyledXYSeries extends XYSeries implements StyledSeries, HasLabel, XYMetaDataset { - private static final Logger log = Logger.getLogger(StyledXYSeries.class); + private static final long serialVersionUID = 1L; - protected Style style; + private final Style style; /** If this Series is to be labelled, use this String as label. */ - protected String label; + private String label; /** The meta data for this series. */ - protected Map<String, String> metaData; + private Map<String, String> metaData; - public StyledXYSeries(String key, ThemeDocument theme) { - this(key, true, theme, (Shape)null); + /** + * A 'type' that allows to categorize themes by it. Tyically this is simply the facet-name of the originating + * {@link Facet}. + * REMARK: stictly there should be a type per dataset, not per series, but flys uses (for line themes) generic datasets + * with one series. + */ + private final String themeType; + + public StyledXYSeries(final String facetName, final String key, final ThemeDocument theme) { + this(facetName, key, true, theme, (Shape) null); } - - public StyledXYSeries( - String key, - ThemeDocument theme, - XYSeries unstyledSeries - ) { - this(key, theme); - add(unstyledSeries); + public StyledXYSeries(final String facetName, final String key, final boolean sorted, final ThemeDocument theme) { + this(facetName, key, sorted, theme, (Shape) null); } - public StyledXYSeries(String key, boolean sorted, ThemeDocument theme) { - this(key, sorted, theme, (Shape)null); - } - - - public StyledXYSeries(String key, ThemeDocument theme, Shape shape) { - this(key, true, theme, shape); + public StyledXYSeries(final String facetName, final String key, final ThemeDocument theme, final Shape shape) { + this(facetName, key, true, theme, shape); } /** - * @param sorted whether or not to sort the points. Sorting will move NANs - * to one extrema which can cause problems in certain - * algorithms. + * @param sorted + * whether or not to sort the points. Sorting will move NANs + * to one extrema which can cause problems in certain + * algorithms. */ - public StyledXYSeries( - String key, - boolean sorted, - ThemeDocument theme, - Shape shape - ) { + public StyledXYSeries(final String facetName, final String key, final boolean sorted, final ThemeDocument theme, final Shape shape) { super(key, sorted); - setStyle(new XYStyle(theme, shape)); + + this.style = new XYStyle(theme, shape); this.label = key.toString(); + this.themeType = facetName; } - public StyledXYSeries( - String key, - boolean sorted, - boolean allowDuplicateXValues, - ThemeDocument theme - ) { - this(key, sorted, allowDuplicateXValues, theme, (Shape)null); + public StyledXYSeries(final String themeType, final String key, final boolean sorted, final boolean allowDuplicateXValues, final ThemeDocument theme) { + this(themeType, key, sorted, allowDuplicateXValues, theme, (Shape) null); } - public StyledXYSeries( - String key, - boolean sorted, - boolean allowDuplicateXValues, - ThemeDocument theme, - Shape shape - ) { + public StyledXYSeries(final String themeType, final String key, final boolean sorted, final boolean allowDuplicateXValues, final ThemeDocument theme, + final Shape shape) { super(key, sorted, allowDuplicateXValues); - setStyle(new XYStyle(theme, shape)); + + this.style = new XYStyle(theme, shape); this.label = key.toString(); + this.themeType = themeType; } - @Override - public void setStyle(Style style) { - this.style = style; + public String getThemeType() { + return this.themeType; } - @Override public Style getStyle() { - return style; + return this.style; } - @Override public String getLabel() { - return label; + return this.label; } @Override - public void setLabel(String label) { + public void setLabel(final String label) { this.label = label; } - protected void add(XYSeries series) { - List<XYDataItem> items = series.getItems(); - add(items); - } - - protected void add(List<XYDataItem> items) { - for(XYDataItem item : items) { - add(item.getXValue(), item.getYValue()); - } - } - - @Override public Map<String, String> getMetaData() { - return metaData; + return this.metaData; } - @Override // FIXME: bad! method with undocumented side-effects; given metadata will be changed inline - public void putMetaData(Map<String, String> metaData, - Artifact artifact, - CallContext context) { + public void putMetaData(final Map<String, String> metaData, final Artifact artifact, final CallContext context) { this.metaData = metaData; - River river = new RiverAccess((D4EArtifact)artifact).getRiver(); + final River river = new RiverAccess((D4EArtifact) artifact).getRiver(); String rivername = ""; String unit = ""; if (river != null) { rivername = river.getName(); // FIXME: this will always return the wst unit, regardless if the series is a water level or not! - unit = river.getWstUnit().getName(); + unit = river.getWstUnit().getName(); } if (metaData.containsKey("X")) { - this.metaData.put("X", - Resources.getMsg( - context.getMeta(), - metaData.get("X"), - new Object[] { rivername })); + this.metaData.put("X", Resources.getMsg(context.getMeta(), metaData.get("X"), new Object[] { rivername })); } if (metaData.containsKey("Y")) { - this.metaData.put("Y", - Resources.getMsg( - context.getMeta(), - metaData.get("Y"), new Object[] { unit })); + this.metaData.put("Y", Resources.getMsg(context.getMeta(), metaData.get("Y"), new Object[] { unit })); } } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : + + @Override + public void applyAggregatedLegendTheme(final LegendItem item, final ThemeDocument theme) { + this.style.applyAggregatedLegendTheme(item, theme); + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/XYStyle.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/XYStyle.java Tue Oct 23 16:26:48 2018 +0200 @@ -14,6 +14,7 @@ import java.awt.geom.Ellipse2D; import org.dive4elements.river.themes.ThemeDocument; +import org.jfree.chart.LegendItem; import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer; /** @@ -170,8 +171,8 @@ if (c != null) r.setSeriesFillPaint(idx, c); - r.setUseFillPaint(c!= null); - + r.setUseFillPaint(c != null); + r.setSeriesShapesFilled(idx, show); r.setSeriesOutlinePaint(idx, c); @@ -219,4 +220,35 @@ public XYLineAndShapeRenderer getRenderer() { return this.renderer; } + + @Override + public void applyAggregatedLegendTheme(final LegendItem item, final ThemeDocument legendTheme) { + + if (this.theme == null) + return; + + if (this.shape != null) + item.setShape(this.shape); + + final Color lineColor = legendTheme.parseLineColorField(); + if (lineColor != null) + item.setLinePaint(lineColor); + + if (legendTheme.getValue(ThemeDocument.SHOW_LINE) != null) + item.setLineVisible(legendTheme.parseShowLine()); + + /* remark cant set line stroke on legend item */ + // applyLineSize(r, idx); + // applyLineType(r, idx); + + /* + * REMARK: we only change the colors, as visibility and such are interdependend and should be the same as the original + * items + */ + final Color c = legendTheme.parsePointColor(); + if (c != null) { + item.setFillPaint(c); + item.setOutlinePaint(c); + } + } } \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/themes/DefaultTheme.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/themes/DefaultTheme.java Tue Oct 23 16:26:48 2018 +0200 @@ -11,139 +11,83 @@ import java.util.HashMap; import java.util.Map; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; -import org.dive4elements.artifacts.common.utils.XMLUtils; -import org.dive4elements.artifacts.common.utils.XMLUtils.ElementCreator; - /** * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> */ -public class DefaultTheme implements Theme { +final class DefaultTheme implements Theme { /** The name of the theme.*/ - protected String name; + private final String name; - /** The description of the theme.*/ - protected String description; + private String facet; - protected String facet; - - protected int index; - + private int index; /** The map storing the fields of this theme.*/ - protected Map<String, ThemeField> fields; + private final Map<String, ThemeField> fields; /** The map storing the attributes of this theme.*/ - protected Map<String, String> attr; + private final Map<String, String> attr; + private final String description; /** * Initializes the components of this Theme. */ - public DefaultTheme(String name, String description) { + public DefaultTheme(final String name, final String description) { this.name = name; this.description = description; - this.fields = new HashMap<String, ThemeField>(); - this.attr = new HashMap<String, String>(); - } - - - public void init(Node config) { + this.fields = new HashMap<>(); + this.attr = new HashMap<>(); } - + @Override public String getName() { - return name; + return this.name; } - public String getDescription() { - return description; + return this.description; } - - public String getFacet() { - return facet; - } - - - public void setFacet(String facet) { + @Override + public void setFacet(final String facet) { this.facet = facet; } - - public int getIndex() { - return index; - } - - - public void setIndex(int index) { + @Override + public void setIndex(final int index) { this.index = index; } - - public void addAttribute(String name, String value) { + public void addAttribute(final String name, final String value) { if (name != null && value != null) { - attr.put(name, value); + this.attr.put(name, value); } } - - public String getAttribute(String name) { - return attr.get(name); - } - - - public void addField(String name, ThemeField field) { + public void addField(final String name, final ThemeField field) { if (name != null && field != null) { - fields.put(name, field); - } - } - - - public void setFieldValue(String name, Object value) { - if (name != null && value != null) { - ThemeField field = fields.get(name); - - if (field != null) { - field.setValue(value); - } + this.fields.put(name, field); } } - - public ThemeField getField(String name) { - return fields.get(name); - } - - - public String getFieldType(String name) { - ThemeField field = fields.get(name); - - return field != null ? field.getType() : null; - } - + @Override + public Document toXML() { + final Document doc = XMLUtils.newDocument(); - public Object getFieldValue(String name) { - ThemeField field = fields.get(name); - - return field != null ? field.getValue() : null; - } - + final ElementCreator cr = new ElementCreator(doc, null, null); - public Document toXML() { - Document doc = XMLUtils.newDocument(); - - ElementCreator cr = new ElementCreator(doc, null, null); - - Element theme = cr.create("theme"); - theme.setAttribute("facet", facet); - theme.setAttribute("index", String.valueOf(index)); + final Element theme = cr.create("theme"); + theme.setAttribute("facet", this.facet); + theme.setAttribute("index", String.valueOf(this.index)); appendAttributes(cr, theme); appendFields(cr, theme); @@ -160,11 +104,11 @@ * @param cr The ElementCreator. * @param theme The document root element. */ - protected void appendAttributes(ElementCreator cr, Element theme) { + protected void appendAttributes(final ElementCreator cr, final Element theme) { - for (Map.Entry<String, String> entry: attr.entrySet()) { - String key = entry.getKey(); - String val = entry.getValue(); + for (final Map.Entry<String, String> entry: this.attr.entrySet()) { + final String key = entry.getKey(); + final String val = entry.getValue(); if (key != null && val != null) { cr.addAttr(theme, key, val); @@ -179,14 +123,13 @@ * @param cr The ElementCreator. * @param theme The document root element. */ - protected void appendFields(ElementCreator cr, Element theme) { + protected void appendFields(final ElementCreator cr, final Element theme) { - for (ThemeField field: fields.values()) { - Document doc = field.toXML(); - Node root = doc.getFirstChild(); + for (final ThemeField field: this.fields.values()) { + final Document doc = field.toXML(); + final Node root = doc.getFirstChild(); theme.appendChild(theme.getOwnerDocument().importNode(root, true)); } } -} -// 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/themes/Theme.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/themes/Theme.java Tue Oct 23 16:26:48 2018 +0200 @@ -9,8 +9,6 @@ package org.dive4elements.river.themes; import org.w3c.dom.Document; -import org.w3c.dom.Node; - /** * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> @@ -18,110 +16,22 @@ public interface Theme { /** - * Method to initialize the theme. - * - * @param config The configuration node. - */ - void init(Node config); - - - /** * Returns the name of the theme. * * @return the name of the theme. */ String getName(); - - /** - * Returns the description of the theme. - * - * @return the description of the theme. - */ String getDescription(); - - String getFacet(); - void setFacet(String facet); - int getIndex(); - void setIndex(int index); - - /** - * Adds a new attribute. - * - * @param name The name of the attribute. - * @param value The value of the attribute. - */ - void addAttribute(String name, String value); - - - /** - * Returns the value of a specific attribute. - * - * @param name the name of the attribute. - * - * @return the value of the attribute <i>name</i>. - */ - String getAttribute(String name); - - - /** - * Adds a new field to the theme. - * - * @param name The name of the field. - * @param field The field. - */ - void addField(String name, ThemeField field); - - - /** - * Sets the value of an field. - * - * @param name The name of the field. - * @param value The new value of the field. - */ - void setFieldValue(String name, Object value); - - - /** - * Returns the field specified by name. - * - * @param name The name of the desired field. - * - * @return an field. - */ - ThemeField getField(String name); - - - /** - * Returns the typename of a field. - * - * @param name the name of the field. - * - * @return the typename of a field. - */ - String getFieldType(String name); - - - /** - * Returns the value of a field. - * - * @param name The name of the field. - * - * @return the value of a field. - */ - Object getFieldValue(String name); - - /** * Dumps the theme to XML. * * @return a document. */ Document toXML(); -} -// 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/themes/ThemeDocument.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/themes/ThemeDocument.java Tue Oct 23 16:26:48 2018 +0200 @@ -34,7 +34,7 @@ private static final String MSG_ISOBATH_CLASS = "floodmap.isobath.class"; private static final String MSG_ISOBATH_LASTCLASS = - "floodmap.isobath.lastclass"; + "floodmap.isobath.lastclass"; public final static String FILL_COLOR = "fillcolor"; @@ -132,35 +132,34 @@ public ThemeDocument() { } - public ThemeDocument(Document document) { - values = extractValues(document); - } - - public ThemeDocument(ThemeDocument other) { - values = new HashMap<String, String>(other.values); + public ThemeDocument(final Document document) { + this.values = extractValues(document); } - - public String getValue(String key) { - return values.get(key); + public ThemeDocument(final ThemeDocument other) { + this.values = new HashMap<>(other.values); } - public void setValue(String key, String value) { - values.put(key, value); + public String getValue(final String key) { + return this.values.get(key); } - private static Map<String, String> extractValues(Document document) { - Map<String, String> values = new HashMap<String, String>(); + public void setValue(final String key, final String value) { + this.values.put(key, value); + } + + private static Map<String, String> extractValues(final Document document) { + final Map<String, String> values = new HashMap<>(); if (document == null) { log.error("Invalid null document given."); return values; } - NodeList fields = document.getElementsByTagName("field"); + final NodeList fields = document.getElementsByTagName("field"); for (int i = 0, N = fields.getLength(); i < N; ++i) { - Element field = (Element)fields.item(i); - String name = field.getAttribute("name"); - String value = field.getAttribute("default"); + final Element field = (Element)fields.item(i); + final String name = field.getAttribute("name"); + final String value = field.getAttribute("default"); if (!name.isEmpty() && !value.isEmpty()) { values.put(name, value); } @@ -172,7 +171,7 @@ } /** Parse string to be boolean with default if empty or unrecognized. */ - private static boolean parseBoolean(String value, boolean defaultsTo) { + private static boolean parseBoolean(final String value, final boolean defaultsTo) { if (value == null) { return defaultsTo; } @@ -193,7 +192,7 @@ * @param defaultsTo Default to return if conversion failed. * @return \param value as integer or defaultsto if conversion failed. */ - private static int parseInteger(String value, int defaultsTo) { + private static int parseInteger(final String value, final int defaultsTo) { if (value == null) { return defaultsTo; } @@ -201,7 +200,7 @@ try { return Integer.parseInt(value); } - catch (NumberFormatException nfe) { + catch (final NumberFormatException nfe) { // do nothing } @@ -216,7 +215,7 @@ * @param defaultsTo Default to return if conversion failed. * @return \param value as integer or defaultsto if conversion failed. */ - private static double parseDouble(String value, double defaultsTo) { + private static double parseDouble(final String value, final double defaultsTo) { if (value == null) { return defaultsTo; } @@ -224,7 +223,7 @@ try { return Double.parseDouble(value); } - catch (NumberFormatException nfe) { + catch (final NumberFormatException nfe) { // do nothing } @@ -232,60 +231,60 @@ } public boolean parseShowLineLabel() { - String show = getValue(SHOW_LINE_LABEL); + final String show = getValue(SHOW_LINE_LABEL); return parseBoolean(show, false); } public boolean parseShowWidth() { - String show = getValue(SHOW_WIDTH); + final String show = getValue(SHOW_WIDTH); return parseBoolean(show, false); } public boolean parseShowLevel() { - String show = getValue(SHOW_LEVEL); + final String show = getValue(SHOW_LEVEL); return parseBoolean(show, false); } public String parseTextOrientation() { - String o = getValue(TEXT_ORIENTATION); + final String o = getValue(TEXT_ORIENTATION); return o != null && "true".equals(o) - ? "horizontal" - : "vertical"; + ? "horizontal" + : "vertical"; } public boolean parseShowMiddleHeight() { - String show = getValue(SHOW_MIDDLE_HEIGHT); + final String show = getValue(SHOW_MIDDLE_HEIGHT); return parseBoolean(show, false); } public boolean parseLabelShowBackground() { - String show = getValue(LABEL_SHOW_BACKGROUND); + final String show = getValue(LABEL_SHOW_BACKGROUND); return parseBoolean(show, false); } public Font parseFont() { - String font = getValue(FONT); + final String font = getValue(FONT); log.debug(" font is " + font); if (font == null) { return null; } - int size = parseFontSize(); - int style = parseFontStyle(); - Font f = new Font(font, style, size); + final int size = parseFontSize(); + final int style = parseFontStyle(); + final Font f = new Font(font, style, size); return f; } public Font parseTextFont() { - String font = getValue(LABEL_FONT_FACE); + final String font = getValue(LABEL_FONT_FACE); if (font == null) { return null; } - int size = parseTextSize(); - int style = parseTextStyle(); - Font f = new Font(font, style, size); + final int size = parseTextSize(); + final int style = parseTextStyle(); + final Font f = new Font(font, style, size); return f; } @@ -298,10 +297,10 @@ } public Color parseTextBackground() { - String color = getLabelBackgroundColorString(); + final String color = getLabelBackgroundColorString(); return color != null - ? parseRGB(color) - : Color.WHITE; + ? parseRGB(color) + : Color.WHITE; } private String getLabelBackgroundColorString() { @@ -309,7 +308,7 @@ } public int parseLineWidth() { - String size = getValue(LINE_SIZE); + final String size = getValue(LINE_SIZE); if (size == null) { return 0; } @@ -317,65 +316,65 @@ try { return Integer.parseInt(size); } - catch (NumberFormatException nfe) { + catch (final NumberFormatException nfe) { log.warn("Unable to set line size from string: '" + size + "'"); } return 0; } public float [] parseLineStyle() { - String dash = getValue(LINE_STYLE); + final String dash = getValue(LINE_STYLE); - float[] def = {10}; + final float[] def = {10}; if (dash == null) { return def; } - String[] pattern = dash.split(","); + final String[] pattern = dash.split(","); if(pattern.length == 1) { return def; } try { - float[] dashes = new float[pattern.length]; + final float[] dashes = new float[pattern.length]; for (int i = 0; i < pattern.length; i++) { dashes[i] = Float.parseFloat(pattern[i]); } return dashes; } - catch (NumberFormatException nfe) { + catch (final NumberFormatException nfe) { log.warn("Unable to set dash from string: '" + dash + "'"); return def; } } public int parsePointWidth() { - String width = getValue(POINT_SIZE); + final String width = getValue(POINT_SIZE); return parseInteger(width, 3); } public Color parsePointColor() { - String color = getValue(POINT_COLOR); + final String color = getValue(POINT_COLOR); return parseColor(color); } public boolean parseShowPoints() { - String show = getValue(SHOW_POINTS); + final String show = getValue(SHOW_POINTS); return parseBoolean(show, false); } public boolean parseShowPointsOutline() { - String show = getValue(SHOW_POINTS_OUTLINE); + final String show = getValue(SHOW_POINTS_OUTLINE); return parseBoolean(show, false); } public boolean parseShowLine() { - String show = getValue(SHOW_LINE); + final String show = getValue(SHOW_LINE); return parseBoolean(show, false); } public int parseFontStyle() { - String style = getValue(TEXT_STYLE); + final String style = getValue(TEXT_STYLE); if (style == null) { return Font.PLAIN; } @@ -390,7 +389,7 @@ } public int parseTextStyle() { - String style = getValue(LABEL_FONT_STYLE); + final String style = getValue(LABEL_FONT_STYLE); if (style == null) { return Font.PLAIN; } @@ -412,35 +411,35 @@ font = parseFont(); } return new TextStyle( - parseTextColor(), - font, - parseTextBackground(), - parseLabelShowBackground(), - !parseTextOrientation().equals("horizontal")); + parseTextColor(), + font, + parseTextBackground(), + parseLabelShowBackground(), + !parseTextOrientation().equals("horizontal")); } public LineStyle parseComplexLineStyle() { return new LineStyle( - parseLineColorField(), - Integer.valueOf(parseLineWidth())); + parseLineColorField(), + Integer.valueOf(parseLineWidth())); } public boolean parseShowVerticalLine() { - String show = getValue(SHOW_VERTICAL_LINE); + final String show = getValue(SHOW_VERTICAL_LINE); return parseBoolean(show, true); } public boolean parseShowHorizontalLine() { - String show = getValue(SHOW_HORIZONTAL_LINE); + final String show = getValue(SHOW_HORIZONTAL_LINE); return parseBoolean(show, true); } public double parseBandWidth() { - String bandWidth = getValue(BANDWIDTH); + final String bandWidth = getValue(BANDWIDTH); return parseDouble(bandWidth, 0); } - private static Color parseColor(String colorString) { + private static Color parseColor(final String colorString) { if (colorString == null) { return null; } @@ -462,35 +461,35 @@ * * @return a Color or null, if <i>hex</i> is empty. */ - private static Color parseHexColor(String hex) { + private static Color parseHexColor(final String hex) { return hex != null - ? Color.decode(hex) - : null; + ? Color.decode(hex) + : null; } public boolean parseShowArea() { - String show = getValue(SHOW_AREA); + final String show = getValue(SHOW_AREA); return parseBoolean(show, false); } public boolean parseShowAreaLabel() { - String show = getValue(SHOW_AREA_LABEL); + final String show = getValue(SHOW_AREA_LABEL); return parseBoolean(show, false); } public boolean parseShowPointLabel() { - String show = getValue(SHOW_POINT_LABEL); + final String show = getValue(SHOW_POINT_LABEL); return parseBoolean(show, false); } public boolean parseShowExtraMark() { - String show = getValue(SHOWEXTRAMARK); + final String show = getValue(SHOWEXTRAMARK); return parseBoolean(show, false); } public int parseFontSize() { - String size = getValue(TEXT_SIZE); + final String size = getValue(TEXT_SIZE); if (size == null) { return 10; } @@ -498,14 +497,14 @@ try { return Integer.parseInt(size); } - catch (NumberFormatException nfe) { + catch (final NumberFormatException nfe) { // Do nothing } return 10; } public int parseTextSize() { - String size = getValue(LABEL_FONT_SIZE); + final String size = getValue(LABEL_FONT_SIZE); if (size == null) { return 10; } @@ -513,7 +512,7 @@ try { return Integer.parseInt(size); } - catch (NumberFormatException nfe) { + catch (final NumberFormatException nfe) { // Do nothing } return 10; @@ -524,18 +523,18 @@ * @param rgbtext Color as string representation, e.g. "255,0,20". * @return Color, null in case of issues. */ - public static Color parseRGB(String rgbtext) { + public static Color parseRGB(final String rgbtext) { if (rgbtext == null) { return null; } - String rgb[] = rgbtext.split(","); + final String rgb[] = rgbtext.split(","); try { return new Color( - Integer.parseInt(rgb[0].trim()), - Integer.parseInt(rgb[1].trim()), - Integer.parseInt(rgb[2].trim())); + Integer.parseInt(rgb[0].trim()), + Integer.parseInt(rgb[1].trim()), + Integer.parseInt(rgb[2].trim())); } - catch (NumberFormatException nfe) { + catch (final NumberFormatException nfe) { // Do nothing } return null; @@ -603,24 +602,24 @@ * @return color. */ public Color parseLineColorField() { - String lineColorStr = getLineColorString(); + final String lineColorStr = getLineColorString(); if (log.isDebugEnabled()) { log.debug("parseLineColorField: lineColorStr = " + - (lineColorStr == null - ? "null" - : lineColorStr)); + (lineColorStr == null + ? "null" + : lineColorStr)); } return parseColor(lineColorStr); } // FIXME: check, this is defined in default.xml, but never used. Instead the StyledAreaSeriesCollection used lineColor etc public Color parseAreaLineColorField() { - String lineColorStr = getAreaLineColorString(); + final String lineColorStr = getAreaLineColorString(); if (log.isDebugEnabled()) { log.debug("parseLineColorField: lineColorStr = " + - (lineColorStr == null + (lineColorStr == null ? "null" - : lineColorStr)); + : lineColorStr)); } return parseColor(lineColorStr); } @@ -649,68 +648,68 @@ * @return String representation of the MapserverStyle */ public String createDynamicMapserverStyle( - float from, - float to, - float step, - CallMeta meta - ) { - MapserverStyle ms = new MapserverStyle(); - - String strStartColor = getValue(WSPLGEN_STARTCOLOR); - Color startColor = strStartColor != null - ? parseColor(strStartColor) - : new Color(178, 201, 215); - String strEndColor = getValue(WSPLGEN_ENDCOLOR); - Color endColor = strEndColor != null - ? parseColor(strEndColor) - : new Color(2, 27, 42); - - to = to >= 0 ? to : 9999; - step = to != from ? step : 1; - - int numClasses = (int)((to - from) / step + 1); + final float from, + float to, + float step, + final CallMeta meta + ) { + final MapserverStyle ms = new MapserverStyle(); - float rd = (endColor.getRed() - startColor.getRed()) - / (float)numClasses; - float gd = (endColor.getGreen() - startColor.getGreen()) - / (float)numClasses; - float bd = (endColor.getBlue() - startColor.getBlue()) - / (float)numClasses; - - for (int n = 0; n < numClasses; n++) { - StringBuilder newColor = new StringBuilder(); - newColor.append(startColor.getRed() + Math.round(n * rd)); - newColor.append(' '); - newColor.append(startColor.getGreen() + Math.round(n * gd)); - newColor.append(' '); - newColor.append(startColor.getBlue() + Math.round(n * bd)); + final String strStartColor = getValue(WSPLGEN_STARTCOLOR); + final Color startColor = strStartColor != null + ? parseColor(strStartColor) + : new Color(178, 201, 215); + final String strEndColor = getValue(WSPLGEN_ENDCOLOR); + final Color endColor = strEndColor != null + ? parseColor(strEndColor) + : new Color(2, 27, 42); - String expr = createWSPLGENClassExpression( - from + n * step, step, n + 1, numClasses); - String name = createWSPLGENClassName( - from + n * step, step, n + 1, numClasses, meta); + to = to >= 0 ? to : 9999; + step = to != from ? step : 1; - Clazz c = new Clazz(name); - Style s = new Style(); - s.setColor(newColor.toString()); - s.setSize(5); + final int numClasses = (int)((to - from) / step + 1); - c.addItem(new Expression("(" + expr + ")")); - c.addItem(s); + final float rd = (endColor.getRed() - startColor.getRed()) + / (float)numClasses; + final float gd = (endColor.getGreen() - startColor.getGreen()) + / (float)numClasses; + final float bd = (endColor.getBlue() - startColor.getBlue()) + / (float)numClasses; - ms.addClazz(c); - } + for (int n = 0; n < numClasses; n++) { + final StringBuilder newColor = new StringBuilder(); + newColor.append(startColor.getRed() + Math.round(n * rd)); + newColor.append(' '); + newColor.append(startColor.getGreen() + Math.round(n * gd)); + newColor.append(' '); + newColor.append(startColor.getBlue() + Math.round(n * bd)); - return ms.toString(); + final String expr = createWSPLGENClassExpression( + from + n * step, step, n + 1, numClasses); + final String name = createWSPLGENClassName( + from + n * step, step, n + 1, numClasses, meta); + + final Clazz c = new Clazz(name); + final Style s = new Style(); + s.setColor(newColor.toString()); + s.setSize(5); + + c.addItem(new Expression("(" + expr + ")")); + c.addItem(s); + + ms.addClazz(c); + } + + return ms.toString(); } protected static String createWSPLGENClassExpression( - float val, - float step, - int idx, - int maxIdx - ) { + final float val, + final float step, + final int idx, + final int maxIdx + ) { if (idx < maxIdx) { return "[DIFF] >= " + val + " AND [DIFF] < " + (val + step); } @@ -731,12 +730,12 @@ * @return */ protected static String createWSPLGENClassName( - float val, - float step, - int idx, - int maxIdx, - CallMeta meta - ) { + final float val, + final float step, + final int idx, + final int maxIdx, + final CallMeta meta + ) { assert meta != null : "CallMeta instance is null"; if (idx < maxIdx) { @@ -749,21 +748,21 @@ public String createMapserverStyle() { - String symbol = getSymbol(); - String backcolor = getLabelBackgroundColorString(); + final String symbol = getSymbol(); + final String backcolor = getLabelBackgroundColorString(); String linecolor = getLineColorString(); if (linecolor == null) { log.warn("createMapserverStyle: linecolor String is empty"); linecolor = "0,128,255"; } - int linewidth = parseLineWidth(); + final int linewidth = parseLineWidth(); - MapserverStyle ms = new MapserverStyle(); + final MapserverStyle ms = new MapserverStyle(); - Clazz c = new Clazz(" "); + final Clazz c = new Clazz(" "); - Style s = new Style(); + final Style s = new Style(); s.setOutlineColor(linecolor.replace(",", " ")); if (backcolor != null) { @@ -774,11 +773,11 @@ s.setSymbol(symbol); c.addItem(s); - String textcolor = getTextColorString(); - int textsize = parseTextSize(); + final String textcolor = getTextColorString(); + final int textsize = parseTextSize(); if (textcolor != null && textsize > 0) { - Label l = new Label(); + final Label l = new Label(); l.setColor(textcolor.replace(",", " ")); l.setSize(textsize); c.addItem(l); @@ -804,7 +803,7 @@ return parseAreaTransparency(50); } - public int parseAreaTransparency(int alpha) { + public int parseAreaTransparency(final int alpha) { return parseInteger(getAreaTransparencyString(), alpha); } @@ -817,13 +816,13 @@ private String getAreaShowBorderString() { return getValue(AREA_SHOW_BORDER); } - - + + public boolean parseCalculateRange() { return parseBoolean(getCalculateRangeString(), false); } - + private String getCalculateRangeString() { return getValue(CALCULATE_RANGE); } @@ -832,11 +831,11 @@ final String patternName = getValue(AREA_BACKGROUND_PATTERN); if( StringUtils.isBlank(patternName) ) return null; - + try { return AreaFillPattern.valueOf(patternName); } - catch (Exception e) { + catch (final Exception e) { log.error(String.format("%s: invalid pattern name: %s", AREA_BACKGROUND_PATTERN, patternName), e); return null; }
--- a/artifacts/src/main/java/org/dive4elements/river/themes/ThemeFactory.java Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/themes/ThemeFactory.java Tue Oct 23 16:26:48 2018 +0200 @@ -8,10 +8,6 @@ package org.dive4elements.river.themes; -import org.dive4elements.artifacts.common.utils.XMLUtils; -import org.dive4elements.river.artifacts.D4EArtifact; -import org.dive4elements.river.artifacts.context.RiverContext; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -20,6 +16,9 @@ import javax.xml.xpath.XPathConstants; import org.apache.log4j.Logger; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.river.artifacts.D4EArtifact; +import org.dive4elements.river.artifacts.context.RiverContext; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; @@ -29,7 +28,7 @@ /** * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> * - * Mapping-matching rules: + * Mapping-matching rules: * */ public class ThemeFactory { @@ -40,23 +39,24 @@ private ThemeFactory() { } - /** * Creates a new theme from <i>config</i>. * - * @param themeCfg The theme config document that is used to fetch parent - * themes. - * @param config The theme config node. + * @param themeCfg + * The theme config document that is used to fetch parent + * themes. + * @param config + * The theme config node. * * @return a new theme. */ - public static Theme createTheme(Document themeCfg, Node config) { - String name = getName(config); - String desc = getDescription(config); + public static Theme createTheme(final Document themeCfg, final Node config) { + final String name = getName(config); + final String desc = getDescription(config); log.trace("Create new theme: " + name); - Theme theme = new DefaultTheme(name, desc); + final DefaultTheme theme = new DefaultTheme(name, desc); parseInherits(themeCfg, config, theme); parseFields(config, theme); @@ -65,26 +65,21 @@ return theme; } - /** * Get first matching theme for facet. * - * @param name Name to match "from" of theme mapping. - * @param pattern String to 'compare' to pattern in mapping. - * @param output Name of the current output + * @param name + * Name to match "from" of theme mapping. + * @param pattern + * String to 'compare' to pattern in mapping. + * @param output + * Name of the current output * * @return First matching theme. */ - public static Theme getTheme( - RiverContext c, - String name, - String pattern, - String output, - String groupName) - { + public static Theme getTheme(final RiverContext c, final String name, final String pattern, final String output, final String groupName) { if (log.isDebugEnabled()) { - log.debug( - "Search theme for: " + name + " - pattern: " + pattern); + log.debug("Search theme for: " + name + " - pattern: " + pattern); } if (c == null || name == null) { @@ -94,15 +89,15 @@ // Fetch mapping and themes. @SuppressWarnings("unchecked") - Map<String, List<ThemeMapping>> map = (Map<String, List<ThemeMapping>>) - c.get(RiverContext.THEME_MAPPING); + final + Map<String, List<ThemeMapping>> map = (Map<String, List<ThemeMapping>>) c.get(RiverContext.THEME_MAPPING); @SuppressWarnings("unchecked") - List<ThemeGroup> tgs = (List<ThemeGroup>) - c.get(RiverContext.THEMES); + final + List<ThemeGroup> tgs = (List<ThemeGroup>) c.get(RiverContext.THEMES); ThemeGroup group = null; - for (ThemeGroup tg: tgs) { + for (final ThemeGroup tg : tgs) { if (tg.getName().equals(groupName)) { group = tg; break; @@ -114,16 +109,16 @@ return null; } - Map<String, Theme> t = group.getThemes(); + final Map<String, Theme> t = group.getThemes(); - D4EArtifact artifact = (D4EArtifact) c.get(RiverContext.ARTIFACT_KEY); + final D4EArtifact artifact = (D4EArtifact) c.get(RiverContext.ARTIFACT_KEY); if (map == null || map.isEmpty() || t == null || t.isEmpty()) { log.warn("No mappings or themes found. Cannot retrieve theme!"); return null; } - List<ThemeMapping> mapping = map.get(name); + final List<ThemeMapping> mapping = map.get(name); if (mapping == null) { log.warn("No theme found for mapping: " + name); @@ -131,77 +126,60 @@ } // Take first mapping of which all conditions are satisfied. - for (ThemeMapping tm: mapping) { - if (name.equals(tm.getFrom()) - && tm.applyPattern(pattern) - && tm.masterAttrMatches(artifact) - && tm.outputMatches(output)) - { - String target = tm.getTo(); + for (final ThemeMapping tm : mapping) { + if (name.equals(tm.getFrom()) && tm.applyPattern(pattern) && tm.masterAttrMatches(artifact) && tm.outputMatches(output)) { + final String target = tm.getTo(); log.debug("Found theme '" + target + "'"); return t.get(target); } } - String msg = - "No theme found for '" + name + - "' with pattern '" + pattern + "' and output " + output + "."; + final String msg = "No theme found for '" + name + "' with pattern '" + pattern + "' and output " + output + "."; log.warn(msg); return null; } - @SuppressWarnings("unchecked") - public static List<ThemeGroup> getThemeGroups(RiverContext c) { - List<ThemeGroup> tgs = (List<ThemeGroup>) - c.get(RiverContext.THEMES); + public static List<ThemeGroup> getThemeGroups(final RiverContext c) { + final List<ThemeGroup> tgs = (List<ThemeGroup>) c.get(RiverContext.THEMES); return tgs; } - @SuppressWarnings("unchecked") - public static List<Theme> getThemes (RiverContext c, String name) { - List<ThemeGroup> tgs = (List<ThemeGroup>) - c.get(RiverContext.THEMES); + public static List<Theme> getThemes(final RiverContext c, final String name) { + final List<ThemeGroup> tgs = (List<ThemeGroup>) c.get(RiverContext.THEMES); if (tgs == null) { return null; } - List<Theme> themes = new ArrayList<Theme>(); - for (ThemeGroup tg: tgs) { + final List<Theme> themes = new ArrayList<>(); + for (final ThemeGroup tg : tgs) { themes.add(tg.getThemeByName(name)); } return themes; } - protected static String getName(Node config) { - return ((Element)config).getAttribute("name"); + private static String getName(final Node config) { + return ((Element) config).getAttribute("name"); } - - protected static String getDescription(Node config) { - return ((Element)config).getAttribute("desc"); + private static String getDescription(final Node config) { + return ((Element) config).getAttribute("desc"); } - - protected static void parseInherits(Document themeCfg, Node cfg, Theme t) { + private static void parseInherits(final Document themeCfg, final Node cfg, final DefaultTheme t) { parseInherits(themeCfg, cfg, t, null); } - protected static void parseInherits( - Document themeCfg, - Node cfg, - Theme t, - Map<String, Node> themes - ) { + private static void parseInherits(final Document themeCfg, final Node cfg, final DefaultTheme t, Map<String, Node> themes) { log.trace("ThemeFactory.parseInherits"); - NodeList inherits = ((Element)cfg).getElementsByTagName("inherit"); + final NodeList inherits = ((Element) cfg).getElementsByTagName("inherit"); - int num = inherits.getLength(); + final int num = inherits.getLength(); if (num == 0) { log.trace("Theme does not inherit from other themes."); @@ -215,43 +193,41 @@ } for (int i = 0; i < num; i++) { - Node inherit = inherits.item(i); - String from = ((Element)inherit).getAttribute("from"); + final Node inherit = inherits.item(i); + final String from = ((Element) inherit).getAttribute("from"); - Node tmp = themes.get(from); + final Node tmp = themes.get(from); parseInherits(themeCfg, tmp, t, themes); parseFields(tmp, t); } } - protected static Map<String, Node> buildThemeMap(Document themeCfg) { - Map<String, Node> map = new HashMap<String, Node>(); - String xpath = "/themes/themegroup/theme"; + private static Map<String, Node> buildThemeMap(final Document themeCfg) { + final Map<String, Node> map = new HashMap<>(); + final String xpath = "/themes/themegroup/theme"; - NodeList nodes = (NodeList)XMLUtils.xpath( - themeCfg, xpath, XPathConstants.NODESET); + final NodeList nodes = (NodeList) XMLUtils.xpath(themeCfg, xpath, XPathConstants.NODESET); if (nodes != null) { for (int i = 0, N = nodes.getLength(); i < N; ++i) { - Node node = nodes.item(i); - String name = ((Element)node).getAttribute("name"); + final Node node = nodes.item(i); + final String name = ((Element) node).getAttribute("name"); map.put(name, node); } } return map; } - - protected static void parseFields(Node config, Theme theme) { + private static void parseFields(final Node config, final DefaultTheme theme) { if (config == null || theme == null) { log.warn("Parsing fields without node or theme is senseless!"); return; } - NodeList fields = ((Element)config).getElementsByTagName("field"); + final NodeList fields = ((Element) config).getElementsByTagName("field"); - int num = fields.getLength(); + final int num = fields.getLength(); log.trace("Found " + num + " own fields in this theme."); @@ -261,34 +237,33 @@ } for (int i = 0; i < num; i++) { - Node field = fields.item(i); + final Node field = fields.item(i); addField(theme, field); } } - - protected static void addField(Theme theme, Node field) { - String name = ((Element)field).getAttribute("name"); + private static void addField(final DefaultTheme theme, final Node field) { + final String name = ((Element) field).getAttribute("name"); log.trace("Add field " + name + " to theme " + theme.getName()); - NamedNodeMap attrs = field.getAttributes(); + final NamedNodeMap attrs = field.getAttributes(); - int num = attrs != null ? attrs.getLength() : 0; + final int num = attrs != null ? attrs.getLength() : 0; if (num == 0) { log.warn("This field has no attributes."); return; } - ThemeField theField = new DefaultThemeField(name); + final ThemeField theField = new DefaultThemeField(name); for (int i = 0; i < num; i++) { - Node attr = attrs.item(i); + final Node attr = attrs.item(i); - String key = attr.getNodeName(); - String value = attr.getNodeValue(); + final String key = attr.getNodeName(); + final String value = attr.getNodeValue(); theField.setAttribute(key, value); } @@ -296,11 +271,10 @@ theme.addField(name, theField); } + private static void parseAttrs(final Node config, final DefaultTheme theme) { + final NamedNodeMap attrs = config.getAttributes(); - protected static void parseAttrs(Node config, Theme theme) { - NamedNodeMap attrs = config.getAttributes(); - - int num = attrs != null ? attrs.getLength() : 0; + final int num = attrs != null ? attrs.getLength() : 0; if (num == 0) { log.trace("Theme has no attributes set."); @@ -308,13 +282,20 @@ } for (int i = 0; i < num; i++) { - Node attr = attrs.item(i); + final Node attr = attrs.item(i); - String name = attr.getNodeName(); - String value = attr.getNodeValue(); + final String name = attr.getNodeName(); + final String value = attr.getNodeValue(); theme.addAttribute(name, value); } } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : + + public static Theme getLegendTheme(final RiverContext flysContext, final String themeType) { + + @SuppressWarnings("unchecked") + final + Map<String, Theme> themes = (Map<String, Theme>) flysContext.get(RiverContext.LEGEND); + return themes.get(themeType); + } +} \ No newline at end of file
--- a/artifacts/src/main/resources/messages.properties Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/resources/messages.properties Tue Oct 23 16:26:48 2018 +0200 @@ -1361,4 +1361,12 @@ state.title.distance_part_state = Select Sub-range state.title.salix.historical.distance_part_state = Select Sub-range state.title.uinfo.bezugswst.miss_vol.distance_part_state = Choose sub-range for the missing depths to be calculated [km] -state.title.distance_only_inundationduration_veg_state = Choose Display Area [km] \ No newline at end of file +state.title.distance_only_inundationduration_veg_state = Choose Display Area [km] + +legend.aggregator.merged = merged + +longitudinal_section.w.legend = h(Q) +longitudinal_section.q.legend = Q +cross_section_water_line.legend = h(Q) +other.wqkms.w.legend = W (Event) +other.wqkms.q.legend = Q (Event) \ No newline at end of file
--- a/artifacts/src/main/resources/messages_de.properties Mon Oct 22 18:26:05 2018 +0200 +++ b/artifacts/src/main/resources/messages_de.properties Tue Oct 23 16:26:48 2018 +0200 @@ -1361,4 +1361,12 @@ state.title.distance_part_state = Festlegen eines Teilabschnitts state.title.salix.historical.distance_part_state = Festlegen eines Teilabschnitts state.title.uinfo.bezugswst.miss_vol.distance_part_state = Strecke der zu ermittelnden Fehltiefen w\u00e4hlen [km] -state.title.distance_only_inundationduration_veg_state = Darstellungsbereich w\u00e4hlen [km] \ No newline at end of file +state.title.distance_only_inundationduration_veg_state = Darstellungsbereich w\u00e4hlen [km] + +legend.aggregator.merged = zusammengefasst + +longitudinal_section.w.legend = W(Q) +longitudinal_section.q.legend = Q +cross_section_water_line.legend = W(Q) +other.wqkms.w.legend = W (Ereignis) +other.wqkms.q.legend = Q (Ereignis) \ No newline at end of file