teichmann@5863: /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde teichmann@5863: * Software engineering by Intevation GmbH teichmann@5863: * teichmann@5863: * This file is Free Software under the GNU AGPL (>=v3) teichmann@5863: * and comes with ABSOLUTELY NO WARRANTY! Check out the teichmann@5863: * documentation coming with Dive4Elements River for details. teichmann@5863: */ teichmann@5863: teichmann@5831: package org.dive4elements.river.exports; felix@3183: felix@3183: import java.awt.geom.Line2D; felix@3183: import java.util.ArrayList; felix@3183: import java.util.HashMap; felix@3183: import java.util.Iterator; christian@4021: import java.util.LinkedHashMap; felix@3183: import java.util.List; felix@3183: felix@3183: import org.jfree.chart.LegendItem; felix@3183: import org.jfree.chart.LegendItemCollection; felix@3183: import org.jfree.chart.plot.XYPlot; felix@3183: felix@3183: felix@3183: /** Class to process Plots legends. */ felix@3183: public abstract class LegendProcessor { felix@3183: felix@3183: /** (Empty) shape for aggregated Legend Items. */ felix@3183: private static final Line2D.Double SPACE = new Line2D.Double(0,0,0,0); sascha@3189: felix@3183: felix@3183: /** Prevent instantiations. */ felix@3183: private LegendProcessor() { felix@3183: } felix@3183: felix@3183: felix@3183: /** felix@3183: * Create a hash from a legenditem. felix@3183: * This hash can then be used to merge legend items labels. felix@3183: * @return hash for given legenditem to identify mergeables. felix@3183: */ felix@3183: protected static String legendItemHash(LegendItem li) { felix@3183: // TODO Do proper implementation. Ensure that only mergable sets are created. felix@3183: // getFillPaint() felix@3183: // getFillPaintTransformer() felix@3183: // getLabel() felix@3183: // getLine() felix@3183: // getLinePaint() felix@3183: // getLineStroke() felix@3183: // getOutminePaint() felix@3183: // getOutlineStroke() felix@3183: // Shape getShape() felix@3183: // String getToolTipText() felix@3183: // String getURLText() felix@3183: // boolean isLineVisible() felix@3183: // boolean isShapeFilled() felix@3183: // boolean isShapeOutlineVisible() felix@3183: // boolean isShapeVisible() felix@3183: String hash = li.getLinePaint().toString(); teichmann@4046: // XXX: DEAD CODE // String label = li.getLabel(); felix@3224: /*if (label.startsWith("W (") || label.startsWith("W(")) { felix@3183: hash += "-W-"; felix@3183: } felix@3183: else if (label.startsWith("Q(") || label.startsWith("Q (")) { felix@3183: hash += "-Q-"; felix@3224: }*/ felix@3183: felix@3183: // WQ.java holds example of using regex Matcher/Pattern. felix@3183: felix@3183: return hash; felix@3183: } felix@3183: felix@3183: felix@3183: /** felix@3183: * Create new legend entries, dependent on settings. felix@3183: * @param plot The plot for which to modify the legend. felix@3183: * @param threshold How many items are needed for aggregation to christian@4021: * be triggered? felix@3183: */ felix@3183: public static void aggregateLegendEntries(XYPlot plot, int threshold) { felix@3183: LegendItemCollection old = plot.getLegendItems(); felix@3183: // Find "similar" entries if aggregation is enabled. felix@3183: felix@3183: int maxListSize = 0; felix@3183: int AGGR_THRESHOLD = threshold; felix@3183: felix@3183: if (AGGR_THRESHOLD > old.getItemCount() || AGGR_THRESHOLD <= 0){ felix@3183: return; felix@3183: } felix@3183: felix@3183: HashMap> entries = new LinkedHashMap>(); christian@4021: for (Iterator i = old.iterator(); i.hasNext();) { christian@4021: LegendItem item = i.next(); felix@3183: String hash = legendItemHash(item); felix@3183: List itemList = entries.get(hash); felix@3183: if (itemList == null) { felix@3183: itemList = new ArrayList(); teichmann@4046: entries.put(hash, itemList); felix@3183: } felix@3183: itemList.add(item); felix@3183: felix@3183: if (itemList.size() > maxListSize) { felix@3183: maxListSize = itemList.size(); felix@3183: } felix@3183: } felix@3183: felix@3183: if (maxListSize < AGGR_THRESHOLD) { felix@3183: // No need to do anything. felix@3183: return; felix@3183: } felix@3183: felix@3183: // Run over collected entries, merge their names and create new felix@3183: // entry if needed. felix@3183: LegendItemCollection newLegend = new LegendItemCollection(); teichmann@4046: for (List itemList: entries.values()) { felix@3183: if (itemList.size() >= AGGR_THRESHOLD) { felix@3183: // Now do merging. teichmann@4046: // XXX: DEAD CODE // LegendItem item = itemList.get(0); felix@3183: // Unfortunately we cannot clone and just setDescription, as this felix@3183: // method was added in JFreeChart 1.0.14 (we are at .13). felix@3183: felix@3183: // Remove the shapes of all but the first items, felix@3183: // to prevent "overfill" of legenditemblock. felix@3183: for (int i = 0; i < itemList.size(); i++) { felix@3183: if (i != 0) { felix@3183: LegendItem litem = itemList.get(i); felix@3183: felix@3183: // Make shape and line really small. felix@3183: LegendItem merged = new LegendItem( felix@3183: "," + litem.getLabel(), litem.getDescription(), litem.getToolTipText(), felix@3183: litem.getURLText(), false, SPACE, felix@3183: false, litem.getFillPaint(), false, felix@3183: litem.getOutlinePaint(), litem.getOutlineStroke(), false, felix@3183: SPACE, litem.getLineStroke(), litem.getLinePaint()); felix@3183: newLegend.add(merged); felix@3183: } felix@3183: else { felix@3183: newLegend.add(itemList.get(i)); felix@3183: } felix@3183: } felix@3183: } felix@3183: else { felix@3183: // Do not merge entries. felix@3183: for (LegendItem li: itemList) { felix@3183: newLegend.add(li); felix@3183: } felix@3183: } felix@3183: } felix@3183: felix@3183: plot.setFixedLegendItems (newLegend); felix@3183: } felix@3183: } felix@3183: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :