[Schmitzm-commits] r721 - trunk/src/schmitzm/jfree/feature/style

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Thu Feb 25 16:25:56 CET 2010


Author: alfonx
Date: 2010-02-25 16:25:55 +0100 (Thu, 25 Feb 2010)
New Revision: 721

Modified:
   trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java
Log:
For BAR charts the design GUI now supports aggregation.

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java	2010-02-25 14:26:02 UTC (rev 720)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java	2010-02-25 15:25:55 UTC (rev 721)
@@ -31,11 +31,17 @@
 
 import hep.aida.bin.StaticBin1D;
 
+import java.awt.Component;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+
 import org.geotools.feature.FeatureCollection;
 import org.jfree.chart.JFreeChart;
 import org.jfree.data.category.CategoryDataset;
@@ -51,673 +57,350 @@
 import schmitzm.lang.ResourceProvider;
 
 /**
- * This interface extends the chart style with several functionalities
- * used to define a chart on a {@link FeatureCollection}.
+ * This interface extends the chart style with several functionalities used to
+ * define a chart on a {@link FeatureCollection}.
+ * 
  * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
  * @version 1.0
  */
 public interface FeatureChartStyle extends ChartStyle {
-  /**
-   * Defines possible aggregation function to calculate 
-   * on attribute categories.
-   * @see FeatureChartStyle#setAttributeAggregation(int, AggregationFunction)
-   * @see FeatureChartStyle#getAttributeAggregation(int)
-   */
-  public static enum AggregationFunction {
-    /** Count of the attribute values. */
-    COUNT,
-    /** Sum of the attribute values. */
-    SUM,
-    /** Sum of the absolute attribute values. */
-    SUM_ABS,
-    /** Average of the attribute values. */
-    AVG,
-    /** Median of the attribute values. */
-    MEDIAN,
-    /** Minimum attribute value. */
-    MIN,
-    /** Maximum attribute value. */
-    MAX,
-    /** Variance of the attribute values. */
-    VARIANCE,
-    /** Standard deviation of the attribute values. */
-    STND_DEV;
-    
-    /**
-     * Prefix for the title (.TITLE) and description (.DESC) key in
-     * the resource bundle.
-     * @see #getTitle()
-     * @see #getDescription() 
-     */
-    public final String RESOURCE_PREFIX = getClass().getSimpleName() + "." + toString();
-    
-    /**
-     * Returns the result of the function from a statistic.
-     * @param statistics Statistic to take the result from.
-     */
-    public Double getResult(StaticBin1D statistics) {
-      switch ( this ) {
-        case AVG: return statistics.mean();
-        case MAX: return statistics.max();
-        case MIN: return statistics.min();
-//        case SUM_ABS: // SK: Man müsste beim "packen der daten in die Statistik" schon abs() auf die werte anwenden und dann diese zeile einkommentieren 
-        case SUM: return statistics.sum();
-        case COUNT: return ((Integer)statistics.size()).doubleValue();
-        case STND_DEV: return statistics.standardDeviation();
-        case VARIANCE: return Math.pow(statistics.standardDeviation(),2);
-        case MEDIAN: return statistics.mean();
-      }
-      throw new UnsupportedOperationException("Aggregation function not yet supported: "+this);
-    }
-    
-    /**
-     * Returns a description of this kind of chart. Can be used for tool-tips.
-     * May return <code>null</code> if no localized String found.
-     */
-    public String getDescription() {
-      final String resource = JFreeChartUtil.R(RESOURCE_PREFIX + ".Desc");
-      if (resource == null || resource.equals(ResourceProvider.MISSING_RESOURCE_STRING))
-        return null;
-      return resource;
-    }
+	/**
+	 * Defines possible aggregation function to calculate on attribute
+	 * categories.
+	 * 
+	 * @see FeatureChartStyle#setAttributeAggregation(int, AggregationFunction)
+	 * @see FeatureChartStyle#getAttributeAggregation(int)
+	 */
+	public static enum AggregationFunction {
+		/** Count of the attribute values. */
+		COUNT,
+		/** Sum of the attribute values. */
+		SUM,
+//		/** Sum of the absolute attribute values. */
+//		SUM_ABS,
+		/** Average of the attribute values. */
+		AVG,
+//		/** Median of the attribute values. */
+//		MEDIAN,
+		/** Minimum attribute value. */
+		MIN,
+		/** Maximum attribute value. */
+		MAX,
+		/** Variance of the attribute values. */
+		VARIANCE,
+		/** Standard deviation of the attribute values. */
+		STND_DEV;
 
-    /**
-     * Returns a localized title of this kind of chart. If no localized string
-     * found, return the Enum.toString()
-     */
-    public String getTitle() {
-      final String resource = JFreeChartUtil.R(RESOURCE_PREFIX + ".Title");
-      if (resource == null || resource.equals(ResourceProvider.MISSING_RESOURCE_STRING))
-        return toString();
-      return resource;
-    }
-  }
+		/**
+		 * Prefix for the title (.TITLE) and description (.DESC) key in the
+		 * resource bundle.
+		 * 
+		 * @see #getTitle()
+		 * @see #getDescription()
+		 */
+		public final String RESOURCE_PREFIX = getClass().getSimpleName() + "."
+				+ toString();
 
-  /**
-   * Returns the maximum number of feature attributes that can be
-   * specified by this style.
-   * @return -1 if there is no limit for range attributes
-   */
-  public int getMaxAttributeCount();
+		/**
+		 * Returns the result of the function from a statistic.
+		 * 
+		 * @param statistics
+		 *            Statistic to take the result from.
+		 */
+		public Double getResult(StaticBin1D statistics) {
+			switch (this) {
+			case AVG:
+				return statistics.mean();
+			case MAX:
+				return statistics.max();
+			case MIN:
+				return statistics.min();
+				// case SUM_ABS: // SK: Man müsste beim
+				// "packen der daten in die Statistik" schon abs() auf die werte
+				// anwenden und dann diese zeile einkommentieren
+			case SUM:
+				return statistics.sum();
+			case COUNT:
+				return ((Integer) statistics.size()).doubleValue();
+			case STND_DEV:
+				return statistics.standardDeviation();
+			case VARIANCE:
+				return Math.pow(statistics.standardDeviation(), 2);
+//			case MEDIAN:
+//			case SUM_ABS:
+			}
+			throw new UnsupportedOperationException(
+					"Aggregation function not yet supported: " + this);
+		}
 
-  /**
-   * Returns the number of feature attributes defined in this style.
-   */
-  public int getAttributeCount();
+		/**
+		 * Returns a description of this kind of chart. Can be used for
+		 * tool-tips. May return <code>null</code> if no localized String found.
+		 */
+		public String getDescription() {
+			final String resource = JFreeChartUtil.R(RESOURCE_PREFIX + ".Desc");
+			if (resource == null
+					|| resource
+							.equals(ResourceProvider.MISSING_RESOURCE_STRING))
+				return null;
+			return resource;
+		}
 
-  /**
-   * Removes all style informations about an attribute and
-   * reorganizes the attribute indexes so there is an continuous 
-   * order. 
-   * @param idx an attribute index
-   */
-  public void removeAttribute(int idx);
+		/**
+		 * Returns a localized title of this kind of chart. If no localized
+		 * string found, return the Enum.toString()
+		 */
+		public String getTitle() {
+			final String resource = JFreeChartUtil
+					.R(RESOURCE_PREFIX + ".Title");
+			if (resource == null
+					|| resource
+							.equals(ResourceProvider.MISSING_RESOURCE_STRING))
+				return toString();
+			return resource;
+		}
 
-  /**
-   * Returns the name of a feature attribute needed to create a
-   * chart for this style.
-   * @param idx attribute index (0=domain; 1=1st range series;
-   *            2=2nd range series; ...)
-   */
-  public String getAttributeName(int idx);
-  
-  /**
-   * Sets the name of a feature attribute needed to create a
-   * chart for this style.
-   * @param idx attribute index (0=domain; 1=1st range series;
-   *            2=2nd range series; ...)
-   * @param attrName feature attribute name 
-   */
-  public void setAttributeName(int idx, String attrName);
-  
-  /**
-   * Creates a chart according to the given 
-   * @param fc  a feature collection
-   * @exception UnsupportedOperationException if the style can not be applied
-   *            to the {@link FeatureCollection} (e.g. the {@link FeatureCollection}
-   *            does not provide the required attributes)
-   */
-  public JFreeChart applyToFeatureCollection(FeatureCollection<SimpleFeatureType, SimpleFeature> fc);
-  
-  /**
-   * Sets whether the features are sorted according to the
-   * domain attribute (before creating a {@link Dataset}).
-   */
-  public void setSortDomainAxis(boolean sort);
+		/**
+		 * A static {@link DefaultListCellRenderer} that will render instances
+		 * of {@link AggregationFunction} with the title and description field
+		 * as a tooltip.
+		 */
+		static ListCellRenderer listCellRenderer = new DefaultListCellRenderer() {
 
-  /**
-   * Returns whether the features are sorted according to the
-   * domain attribute (before creating a {@link Dataset}).
-   * @return {@code false} as default
-   */
-  public boolean isSortDomainAxis();
+			@Override
+			public Component getListCellRendererComponent(JList list,
+					Object value, int index, boolean isSelected,
+					boolean cellHasFocus) {
 
-  /** 
-   * Sets whether a {@link CategoryDataset} is forced for
-   * a numeric domain attribute. The default is to create {@link XYDataset}
-   * for a numeric and {@link CategoryDataset} for a non-numeric domain
-   * attribute.
-   */
-  public void setForceCategories(boolean forceCategories);
+				Component proto = super.getListCellRendererComponent(list,
+						value, index, isSelected, cellHasFocus);
 
-  /** 
-   * Returns whether a {@link CategoryDataset} is forced for
-   * a numeric domain attribute. The default is to create {@link XYDataset}
-   * for a numeric and {@link CategoryDataset} for a non-numeric domain
-   * attribute.
-   * @return {@code false} as default
-   */
-  public boolean isForceCategories();
-  
-  /** 
-   * Sets whether the attribute data is normalized for an
-   * attribute (before creating a {@link Dataset}).
-   * @param idx attribute index (0=domain; 1=1st range series;
-   *            2=2nd range series; ...)
-   * @param normalize indicates the normalize property
-   */  
-  public void setAttributeNormalized(int idx, Boolean normalize);
-	
-  /** 
-   * Returns whether the attribute data is normalized for an
-   * attribute (before creating a {@link Dataset}).
-   * @param idx attribute index (0=domain; 1=1st range series;
-   *            2=2nd range series; ...)
-   * @return {@code false} as default
-   */  
-  public boolean isAttributeNormalized(int idx);
-  
-  /** 
-   * Sets an arithmetical function which is calculated on
-   * the attribute values (when creating a {@link Dataset}
-   * from Features).
-   * The function is calculated on all values with the same
-   * domain value (X/category). If no function is set, duplicate
-   * domain values are ignored (only the "last" value is shown, because
-   * of replacement behavior).
-   * @param idx attribute index (1=1st range series;
-   *            2=2nd range series; ...)
-   * @param func defines the calculated function
-   * @exception IllegalArgumentException if function is set on
-   *            domain attribute (0)
-   */  
-  public void setAttributeAggregation(int idx, AggregationFunction func);
-    
-  /** 
-   * Returns an arithmetical function which is calculated on
-   * the attribute values (when creating a {@link Dataset}
-   * from Features).
-   * The function is calculated on all values with the same
-   * domain value (X/category). If no function is set, duplicate
-   * domain values are ignored (only the "last" value is shown, because
-   * of replacement behavior).
-   * @param idx attribute index (1=1st range series;
-   *            2=2nd range series; ...)
-   * @return {@code null} for index 0 (domain axis)
-   */  
-  public AggregationFunction getAttributeAggregation(int idx);
+				if (proto instanceof JLabel
+						&& value instanceof AggregationFunction) {
+					((JLabel) proto).setText(((AggregationFunction) value)
+							.getTitle());
+					((JLabel) proto)
+							.setToolTipText(((AggregationFunction) value)
+									.getDescription());
+				}
 
-  /**
-   * Sets the values, which are interpreted as "No Data". 
-   * @param idx attribute index the "No Data" values are set for
-   * @param noDataValues the "No Data" values
-   */
-  public void setNoDataValues(int idx, Set<Object> noDataValues);
-  
-  /**
-   * Returns the values, which are interpreted as "No Data". 
-   * @param idx attribute index the "No Data" values are returned for
-   */
-  public Set<Object> getNoDataValues(int idx);
-  
-  /**
-   * Sets a value, which is interpreted as "No Data". 
-   * @param idx attribute index the "No Data" value is set for
-   * @param noDataValue the "No Data" value
-   */
-  public void addNoDataValue(int idx, Object noDataValue);
+				return proto;
+			}
+		};
 
-  /**
-   * Removes a "No Data" value for an attribute. 
-   * @param idx attribute index the "No Data" value is removed for
-   * @param noDataValue the "No Data" value to remove
-   * @return {@code false} if the value was not an "No Data" value 
-   */
-  public boolean removeNoDataValue(int idx, Object noDataValue);
-  
-  /**
-   * Checks whether the given value is one of the "No data" values for
-   * the attribute.
-   * @param idx attribute index the "No Data" value is checked for
-   * @param value an attribute value
-   */
-  public boolean isNoDataValue(int idx, Object value);
+		/**
+		 * Returns a {@link ListCellRenderer} that will render elemnts of type
+		 * {@link AggregationFunction} with their title and description as
+		 * tooltip
+		 **/
+		public static ListCellRenderer getListCellRenderer() {
+			return listCellRenderer;
+		}
+	}
 
-  /**
-   * Checks whether the given value is one of the "No data" values for
-   * the attribute. In this case this method returns {@code null}, otherwise
-   * the value itself.
-   * @param idx attribute index the "No Data" value is checked for
-   * @param value an attribute value
-   * @return {@code null} if the given value is one of the "No data" values 
-   */
-  public <T> T filterNoDataValue(int idx, T value);
-  
-  /**
-   * Updates the unitVisible parameter for all axes at once.
-   * @param visible
-   *            <code>true</code> if unit string shall be displayed in the
-   *            chart.
-   */
-  public void setUnitVisible(boolean visible);
+	/**
+	 * Returns the maximum number of feature attributes that can be specified by
+	 * this style.
+	 * 
+	 * @return -1 if there is no limit for range attributes
+	 */
+	public int getMaxAttributeCount();
 
-  /**
-   * This class defines a dummy implementation of {@link FeatureChartStyle} just
-   * to maintain the properties of the interface {@link FeatureChartStyle}, so
-   * sub classes of {@link FeatureChartStyle} which usually are derived from
-   * a normal {@link ChartStyle} implementation must not implement the
-   * {@link FeatureChartStyle} maintenance each. Instead they can create an
-   * instance of this dummy an pipe their method implementations to the
-   * dummy!<br>
-   * <br>
-   * The {@link #applyToFeatureCollection(FeatureCollection)} and 
-   * {@link #applyToDataset(Dataset)} methods are not implemented by the dummy,
-   * but throw an exception instead!! 
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-   */
-  public static class Dummy extends AbstractChartStyle implements FeatureChartStyle {
-    /** Indicates whether the features are sorted according to the
-     *  domain attribute (before creating a {@link Dataset}). */
-    protected boolean sortDomainAxis;
-    /** Indicates whether a {@link CategoryDataset} is forced for
-     *  a numeric domain attribute. The default is to create {@link XYDataset}
-     *  for a numeric and {@link CategoryDataset} for a non-numeric domain
-     *  attribute. */
-    protected boolean forceCategories;
+	/**
+	 * Returns the number of feature attributes defined in this style.
+	 */
+	public int getAttributeCount();
 
-    /** Holds the attributes needed to specify the chart data
-     *  from feature collection (0 = attribute for domain axis; others assigned
-     *  to the range axis as series). */
-    protected Map<Integer,String> attrNames = new HashMap<Integer,String>();
-    
-    /** Indicates for each attribute whether the attribute data is normalized
-     *  (before creating a {@link Dataset}). */
-    protected Map<Integer,Boolean> normalizeAttr = new HashMap<Integer,Boolean>();
-    
-    /** Holds the maximum number of attributes the style can be defined
-     *  defined for (-1 = no limit). */
-    protected int maxAttrCount = -1;
+	/**
+	 * Removes all style informations about an attribute and reorganizes the
+	 * attribute indexes so there is an continuous order.
+	 * 
+	 * @param idx
+	 *            an attribute index
+	 */
+	public void removeAttribute(int idx);
 
-    /** Holds the number of attributes the style is defined for. */
-    protected int maxAttrIdx = 0;
-    
-    /** Holds the "No Data" values for each attribute. */
-    protected Map<Integer,Set<Object>> noDataValues = new HashMap<Integer, Set<Object>>();
+	/**
+	 * Returns the name of a feature attribute needed to create a chart for this
+	 * style.
+	 * 
+	 * @param idx
+	 *            attribute index (0=domain; 1=1st range series; 2=2nd range
+	 *            series; ...)
+	 */
+	public String getAttributeName(int idx);
 
-    /** Holds the aggregation function for each attribute. */
-    protected Map<Integer,AggregationFunction> aggrFuncs = new HashMap<Integer, AggregationFunction>();
+	/**
+	 * Sets the name of a feature attribute needed to create a chart for this
+	 * style.
+	 * 
+	 * @param idx
+	 *            attribute index (0=domain; 1=1st range series; 2=2nd range
+	 *            series; ...)
+	 * @param attrName
+	 *            feature attribute name
+	 */
+	public void setAttributeName(int idx, String attrName);
 
-    /**
-     * Creates a new dummy. This constructor is protected so that only derived
-     * classes can instantiate a dummy! There is no limit for the number
-     * of attributes which can be defined by the style.
-     * @param id a (unique) ID for the style
-     */
-    protected Dummy(String id) {
-      this(id,-1);
-    }
+	/**
+	 * Creates a chart according to the given
+	 * 
+	 * @param fc
+	 *            a feature collection
+	 * @exception UnsupportedOperationException
+	 *                if the style can not be applied to the
+	 *                {@link FeatureCollection} (e.g. the
+	 *                {@link FeatureCollection} does not provide the required
+	 *                attributes)
+	 */
+	public JFreeChart applyToFeatureCollection(
+			FeatureCollection<SimpleFeatureType, SimpleFeature> fc);
 
-    /**
-     * Creates a new dummy. This constructor is protected so that only derived
-     * classes can instantiate a dummy!
-     * @param id  a (unique) ID for the style
-     * @param maxAttrCount attribute count needed to specify the chart data
-     *                     from feature collection
-     */
-    protected Dummy(String id, int maxAttrCount) {
-      super(id);
-      this.maxAttrCount = maxAttrCount;
-    }
+	/**
+	 * Sets whether the features are sorted according to the domain attribute
+	 * (before creating a {@link Dataset}).
+	 */
+	public void setSortDomainAxis(boolean sort);
 
-    /**
-     * Updates the local variable for the number of attributes
-     * the maximum index (key) of the several hash maps. 
-     */
-    private void updateAttributeCount() {
-      // attribute names define the number of attributes, also
-      // if there are "more" normalize constraints specified
-      maxAttrIdx = LangUtil.max( attrNames.keySet(),
-                                 normalizeAttr.keySet(),
-                                 noDataValues.keySet() );
-      
-      if ( maxAttrCount > 0 && maxAttrIdx >= maxAttrCount )
-        throw new IllegalArgumentException("Only "+maxAttrCount+" attributes can be specified for "+LangUtil.getSimpleClassName(this));
-    }
-    
-    /**
-     * Removes all style informations about an attribute and
-     * reorganizes the attribute indexes so there is an continuous 
-     * order. 
-     * @param idx an attribute
-     */
-    @Override
-    public void removeAttribute(int idx) {
-      // clear sets and maps of the removed attribute
-      Set<Object> noDataValues = getNoDataValues(idx);
-      if ( noDataValues != null )
-        noDataValues.clear();
-      
-      // remove the attribute by move the "greater" attributes
-      // one position "forward"
-      int maxIdx = getAttributeCount()-1;
-      for (int i=idx; i<maxIdx; i++) {
-        this.attrNames.put(i, this.attrNames.get(i+1));
-        this.normalizeAttr.put(i, this.normalizeAttr.get(i+1));
-        this.noDataValues.put(i, this.noDataValues.get(i+1));
-      }
-      
-      // delete the last attribute, because now is is stored
-      // one position forward
-      this.attrNames.remove(maxIdx);
-      this.normalizeAttr.remove(maxIdx);
-      this.noDataValues.remove(maxIdx);
-      
-      updateAttributeCount();
-    }
-    
-    /**
-     * Creates a (deep) clone of this style. The properties
-     * of the super class ({@link AbstractChartStyle}) are <b>ignored</b>
-     * because they are unused for the dummy.
-     */
-    @Override
-    public AbstractChartStyle copy() {
-      return (AbstractChartStyle)copyTo( (FeatureChartStyle)new Dummy("") );
-    }
-    
-    /**
-     * Copies all properties of this style to another one. The properties
-     * of the super class ({@link AbstractChartStyle}) are <b>ignored</b>
-     * because they are unused for the dummy.
-     * @param dest destination object (if {@code null} the copy
-     *             is created by {@link #copy()})
-     * @return {@code dest} or the new instance
-     */
-    @Override
-    public ChartStyle copyTo(ChartStyle dest) {
-      // !! do NOT copy the super class properties  !!
-      // !! copy only this classes properties       !!
-      // !! Reason: the dummy does not maintain the !!
-      // !!         super class properties and we   !!
-      //            do not want to overwrite them   !!
-      if ( dest instanceof FeatureChartStyle ) {
-        FeatureChartStyle destFCS = (FeatureChartStyle) dest;
-        destFCS.setSortDomainAxis( isSortDomainAxis() );
-        destFCS.setForceCategories( isForceCategories() );
+	/**
+	 * Returns whether the features are sorted according to the domain attribute
+	 * (before creating a {@link Dataset}).
+	 * 
+	 * @return {@code false} as default
+	 */
+	public boolean isSortDomainAxis();
 
-        // Clear the attribute names and attribute normalization
-        int max = destFCS.getMaxAttributeCount();
-        for (int i=0; i<max; i++) {
-          destFCS.setAttributeName(i, null);
-          destFCS.setAttributeNormalized(i, null);
-          
-          // Added by SK. In this special case we don't 
-          destFCS.setNoDataValues(i, getNoDataValues(i));
-        }
-        // Copy attribute names and normalization
-        for (Integer idx : attrNames.keySet() )
-          if ( getAttributeName(idx) != null )
-            destFCS.setAttributeName(idx, getAttributeName(idx));
-        for (Integer idx : normalizeAttr.keySet() )
-          if ( isAttributeNormalized(idx) )
-            destFCS.setAttributeNormalized(idx, isAttributeNormalized(idx));
-        
-      }
-      
-      return dest;
-    }
+	/**
+	 * Sets whether a {@link CategoryDataset} is forced for a numeric domain
+	 * attribute. The default is to create {@link XYDataset} for a numeric and
+	 * {@link CategoryDataset} for a non-numeric domain attribute.
+	 */
+	public void setForceCategories(boolean forceCategories);
 
-    /**
-     * Returns the maximum number of feature attributes that can be
-     * specified by this style.
-     * @return -1 if there is no limit for range attributes
-     */
-    @Override
-    public int getMaxAttributeCount() {
-      return maxAttrCount;
-    }
+	/**
+	 * Returns whether a {@link CategoryDataset} is forced for a numeric domain
+	 * attribute. The default is to create {@link XYDataset} for a numeric and
+	 * {@link CategoryDataset} for a non-numeric domain attribute.
+	 * 
+	 * @return {@code false} as default
+	 */
+	public boolean isForceCategories();
 
-    /**
-     * Returns the number of feature attributes defined in this style.
-     */
-    @Override
-    public int getAttributeCount() {
-      return maxAttrIdx+1;
-    }
+	/**
+	 * Sets whether the attribute data is normalized for an attribute (before
+	 * creating a {@link Dataset}).
+	 * 
+	 * @param idx
+	 *            attribute index (0=domain; 1=1st range series; 2=2nd range
+	 *            series; ...)
+	 * @param normalize
+	 *            indicates the normalize property
+	 */
+	public void setAttributeNormalized(int idx, Boolean normalize);
 
-    /**
-     * Returns the name of a feature attribute needed to create a
-     * chart for this style.
-     * @param idx attribute index (0=domain; 1=1st range series;
-     *            2=2nd range series; ...)
-     */
-    @Override
-   public String getAttributeName(int idx) {
-      return attrNames.get(idx);
-    }
+	/**
+	 * Returns whether the attribute data is normalized for an attribute (before
+	 * creating a {@link Dataset}).
+	 * 
+	 * @param idx
+	 *            attribute index (0=domain; 1=1st range series; 2=2nd range
+	 *            series; ...)
+	 * @return {@code false} as default
+	 */
+	public boolean isAttributeNormalized(int idx);
 
-    /**
-     * Sets the name of a feature attribute needed to create a
-     * chart for this style.
-     * @param idx attribute index (0=domain; 1=1st range series;
-     *            2=2nd range series; ...)
-     * @param attrName feature attribute name 
-     */
-    @Override
-    public void setAttributeName(int idx, String attrName) {
-      attrNames.put(idx,attrName);
-      updateAttributeCount();
-    }
+	/**
+	 * Sets an arithmetical function which is calculated on the attribute values
+	 * (when creating a {@link Dataset} from Features). The function is
+	 * calculated on all values with the same domain value (X/category). If no
+	 * function is set, duplicate domain values are ignored (only the "last"
+	 * value is shown, because of replacement behavior).
+	 * 
+	 * @param idx
+	 *            attribute index (1=1st range series; 2=2nd range series; ...)
+	 * @param func
+	 *            defines the calculated function
+	 * @exception IllegalArgumentException
+	 *                if function is set on domain attribute (0)
+	 */
+	public void setAttributeAggregation(int idx, AggregationFunction func);
 
+	/**
+	 * Returns an arithmetical function which is calculated on the attribute
+	 * values (when creating a {@link Dataset} from Features). The function is
+	 * calculated on all values with the same domain value (X/category). If no
+	 * function is set, duplicate domain values are ignored (only the "last"
+	 * value is shown, because of replacement behavior).
+	 * 
+	 * @param idx
+	 *            attribute index (1=1st range series; 2=2nd range series; ...)
+	 * @return {@code null} for index 0 (domain axis)
+	 */
+	public AggregationFunction getAttributeAggregation(int idx);
 
-    /**
-     * Sets whether the features are sorted according to the
-     * domain attribute (before creating a {@link Dataset}).
-     */
-    @Override
-  	public void setSortDomainAxis(boolean sortDomainAxis){
-		this.sortDomainAxis = sortDomainAxis;
-  	}
-  	
-    /**
-     * Returns whether the features are sorted according to the
-     * domain attribute (before creating a {@link Dataset}).
-     * @return {@code false} as default
-     */
-    @Override
-    public boolean isSortDomainAxis() {
-		return sortDomainAxis;
-	}
-    
-    /** 
-     * Sets whether a {@link CategoryDataset} is forced for
-     * a numeric domain attribute. The default is to create {@link XYDataset}
-     * for a numeric and {@link CategoryDataset} for a non-numeric domain
-     * attribute.
-     */
-    @Override
-  	public void setForceCategories(boolean forceCategories){
-		this.forceCategories = forceCategories;
-  	}
-  	
-    /** 
-     * Returns whether a {@link CategoryDataset} is forced for
-     * a numeric domain attribute. The default is to create {@link XYDataset}
-     * for a numeric and {@link CategoryDataset} for a non-numeric domain
-     * attribute.
-     * @return {@code false} as default
-     */
-    @Override
-    public boolean isForceCategories(){
-    	return forceCategories;
-    }
+	/**
+	 * Sets the values, which are interpreted as "No Data".
+	 * 
+	 * @param idx
+	 *            attribute index the "No Data" values are set for
+	 * @param noDataValues
+	 *            the "No Data" values
+	 */
+	public void setNoDataValues(int idx, Set<Object> noDataValues);
 
-    /** 
-     * Sets whether the attribute data is normalized for an
-     * attribute (before creating a {@link Dataset}).
-  	 * @param idx attribute index (0=domain; 1=1st range series;
-  	 *            2=2nd range series; ...)
-  	 * @param normalize indicates the normalize property
-  	 */  
-    @Override
-  	public void setAttributeNormalized(int idx, Boolean normalize){
-      normalizeAttr.put(idx, normalize);
-      updateAttributeCount();
-  	}
+	/**
+	 * Returns the values, which are interpreted as "No Data".
+	 * 
+	 * @param idx
+	 *            attribute index the "No Data" values are returned for
+	 */
+	public Set<Object> getNoDataValues(int idx);
 
-    /** 
-     * Returns whether the attribute data is normalized for an
-     * attribute (before creating a {@link Dataset}).
-     * @param idx attribute index (0=domain; 1=1st range series;
-     *            2=2nd range series; ...)
-     * @return {@code false} as default
-     */  
-  	@Override
-	public boolean isAttributeNormalized(int idx) {
-	  Boolean normalize = normalizeAttr.get(idx);
-	  return normalize != null && normalize;
-	}
+	/**
+	 * Sets a value, which is interpreted as "No Data".
+	 * 
+	 * @param idx
+	 *            attribute index the "No Data" value is set for
+	 * @param noDataValue
+	 *            the "No Data" value
+	 */
+	public void addNoDataValue(int idx, Object noDataValue);
 
-    /** 
-     * Sets an arithmetical function which is calculated on
-     * the attribute values (when creating a {@link Dataset}
-     * from Features).
-     * The function is calculated on all values with the same
-     * domain value (X/category). If no function is set, duplicate
-     * domain values are ignored (only the "last" value is shown, because
-     * of replacement behavior).
-     * @param idx attribute index (1=1st range series;
-     *            2=2nd range series; ...)
-     * @param func defines the calculated function
-     * @exception IllegalArgumentException if function is set on
-     *            domain attribute (0)
-     */  
-    @Override
-    public void setAttributeAggregation(int idx, AggregationFunction func) {
-      if ( idx == 0 )
-        throw new IllegalArgumentException("Aggregation function not allowed for attribute 0 (domain attribute)!");
-      aggrFuncs.put(idx, func);
-    }
-      
-    /** 
-     * Returns an arithmetical function which is calculated on
-     * the attribute values (when creating a {@link Dataset}
-     * from Features).
-     * The function is calculated on all values with the same
-     * domain value (X/category). If no function is set, duplicate
-     * domain values are ignored (only the "last" value is shown, because
-     * of replacement behavior).
-     * @param idx attribute index (1=1st range series;
-     *            2=2nd range series; ...)
-     * @return {@code null} for index 0 (domain axis)
-     */  
-    @Override
-    public AggregationFunction getAttributeAggregation(int idx) {
-     if ( idx == 0 )
-       return null;
-     return aggrFuncs.get(idx); 
-    }
+	/**
+	 * Removes a "No Data" value for an attribute.
+	 * 
+	 * @param idx
+	 *            attribute index the "No Data" value is removed for
+	 * @param noDataValue
+	 *            the "No Data" value to remove
+	 * @return {@code false} if the value was not an "No Data" value
+	 */
+	public boolean removeNoDataValue(int idx, Object noDataValue);
 
-    /**
-     * Sets the values, which are interpreted as "No Data". 
-     * @param idx attribute index the "No Data" values are set for
-     * @param noDataValues the "No Data" values
-     */
-    public void setNoDataValues(int idx, Set<Object> noDataValues) {
-      this.noDataValues.put(idx, noDataValues);
-      updateAttributeCount();
-    }
-    
-    /**
-     * Returns the values, which are interpreted as "No Data". 
-     * @param idx attribute index the "No Data" values are returned for
-     */
-    public Set<Object> getNoDataValues(int idx) {
-      return this.noDataValues.get(idx);
-    }
-    
-    /**
-     * Sets a value, which is interpreted as "No Data". 
-     * @param idx attribute index the "No Data" value is set for
-     * @param noDataValue the "No Data" value
-     */
-    public void addNoDataValue(int idx, Object noDataValue) {
-      Set<Object> noDataValues = getNoDataValues(idx);
-      if ( noDataValues == null ) {
-        noDataValues = new HashSet<Object>();
-        setNoDataValues(idx, noDataValues);
-      }
-      noDataValues.add(noDataValue);
-    }
+	/**
+	 * Checks whether the given value is one of the "No data" values for the
+	 * attribute.
+	 * 
+	 * @param idx
+	 *            attribute index the "No Data" value is checked for
+	 * @param value
+	 *            an attribute value
+	 */
+	public boolean isNoDataValue(int idx, Object value);
 
-    /**
-     * Removes a "No Data" value for an attribute. 
-     * @param idx attribute index the "No Data" value is removed for
-     * @param noDataValue the "No Data" value to remove
-     * @return {@code false} if the value was not an "No Data" value 
-     */
-    public boolean removeNoDataValue(int idx, Object noDataValue) {
-      Set<Object> noDataValues = getNoDataValues(idx);
-      if ( noDataValues == null )
-        return false;
-      return noDataValues.remove(noDataValue);
-    }
+	/**
+	 * Checks whether the given value is one of the "No data" values for the
+	 * attribute. In this case this method returns {@code null}, otherwise the
+	 * value itself.
+	 * 
+	 * @param idx
+	 *            attribute index the "No Data" value is checked for
+	 * @param value
+	 *            an attribute value
+	 * @return {@code null} if the given value is one of the "No data" values
+	 */
+	public <T> T filterNoDataValue(int idx, T value);
 
-    /**
-     * Checks whether the given value is one of the "No data" values for
-     * the attribute.
-     * @param idx attribute index the "No Data" value is checked for
-     * @param value an attribute value
-     */
-    public boolean isNoDataValue(int idx, Object value) {
-      Set<Object> noDataValues = getNoDataValues(idx);
-      if ( noDataValues == null )
-        return false;
-      return noDataValues.contains(value);
-    }
-
-    /**
-     * Checks whether the given value is one of the "No data" values for
-     * the attribute. In this case this method returns {@code null}, otherwise
-     * the value itself.
-     * @param idx attribute index the "No Data" value is checked for
-     * @param value an attribute value
-     * @return {@code null} if the given value is one of the "No data" values 
-     */
-    public <T> T filterNoDataValue(int idx, T value) {
-      if ( isNoDataValue(idx, value) )
-        return null;
-      return value;
-    }
-
-    /**
-     * Does nothing, but always throws a {@link UnsupportedOperationException},
-     * because the dummy can not provide this functionality.
-     */
-    @Override
-    public JFreeChart applyToDataset(Dataset dataset) {
-      throw new UnsupportedOperationException("FeatureChartStyle.Dummy does not implement applyToDataset(..)");
-    }
-
-    /**
-     * Does nothing, but always throws a {@link UnsupportedOperationException},
-     * because the dummy can not provide this functionality.
-     */
-    @Override
-    public JFreeChart applyToFeatureCollection(FeatureCollection<SimpleFeatureType, SimpleFeature> fc) {
-      throw new UnsupportedOperationException("FeatureChartStyle.Dummy does not implement applyToFeatureCollection(..)");
-    }
-
 	/**
 	 * Updates the unitVisible parameter for all axes at once.
 	 * 
@@ -725,15 +408,489 @@
 	 *            <code>true</code> if unit string shall be displayed in the
 	 *            chart.
 	 */
-	@Override
-	public void setUnitVisible(boolean visible) {
-		// TODO MArtin! Funktioniert so leider nicht. Warum ist hier getAxisCount() immer 0 ????
-		for (int axisIndex = 0; axisIndex < getAxisCount(); axisIndex++) {
-			getAxisStyle(axisIndex).setUnitVisible(visible);
+	public void setUnitVisible(boolean visible);
+
+	/**
+	 * This class defines a dummy implementation of {@link FeatureChartStyle}
+	 * just to maintain the properties of the interface
+	 * {@link FeatureChartStyle}, so sub classes of {@link FeatureChartStyle}
+	 * which usually are derived from a normal {@link ChartStyle} implementation
+	 * must not implement the {@link FeatureChartStyle} maintenance each.
+	 * Instead they can create an instance of this dummy an pipe their method
+	 * implementations to the dummy!<br>
+	 * <br>
+	 * The {@link #applyToFeatureCollection(FeatureCollection)} and
+	 * {@link #applyToDataset(Dataset)} methods are not implemented by the
+	 * dummy, but throw an exception instead!!
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 */
+	public static class Dummy extends AbstractChartStyle implements
+			FeatureChartStyle {
+		/**
+		 * Indicates whether the features are sorted according to the domain
+		 * attribute (before creating a {@link Dataset}).
+		 */
+		protected boolean sortDomainAxis;
+		/**
+		 * Indicates whether a {@link CategoryDataset} is forced for a numeric
+		 * domain attribute. The default is to create {@link XYDataset} for a
+		 * numeric and {@link CategoryDataset} for a non-numeric domain
+		 * attribute.
+		 */
+		protected boolean forceCategories;
+
+		/**
+		 * Holds the attributes needed to specify the chart data from feature
+		 * collection (0 = attribute for domain axis; others assigned to the
+		 * range axis as series).
+		 */
+		protected Map<Integer, String> attrNames = new HashMap<Integer, String>();
+
+		/**
+		 * Indicates for each attribute whether the attribute data is normalized
+		 * (before creating a {@link Dataset}).
+		 */
+		protected Map<Integer, Boolean> normalizeAttr = new HashMap<Integer, Boolean>();
+
+		/**
+		 * Holds the maximum number of attributes the style can be defined
+		 * defined for (-1 = no limit).
+		 */
+		protected int maxAttrCount = -1;
+
+		/** Holds the number of attributes the style is defined for. */
+		protected int maxAttrIdx = 0;
+
+		/** Holds the "No Data" values for each attribute. */
+		protected Map<Integer, Set<Object>> noDataValues = new HashMap<Integer, Set<Object>>();
+
+		/** Holds the aggregation function for each attribute. */
+		protected Map<Integer, AggregationFunction> aggrFuncs = new HashMap<Integer, AggregationFunction>();
+
+		/**
+		 * Creates a new dummy. This constructor is protected so that only
+		 * derived classes can instantiate a dummy! There is no limit for the
+		 * number of attributes which can be defined by the style.
+		 * 
+		 * @param id
+		 *            a (unique) ID for the style
+		 */
+		protected Dummy(String id) {
+			this(id, -1);
 		}
+
+		/**
+		 * Creates a new dummy. This constructor is protected so that only
+		 * derived classes can instantiate a dummy!
+		 * 
+		 * @param id
+		 *            a (unique) ID for the style
+		 * @param maxAttrCount
+		 *            attribute count needed to specify the chart data from
+		 *            feature collection
+		 */
+		protected Dummy(String id, int maxAttrCount) {
+			super(id);
+			this.maxAttrCount = maxAttrCount;
+		}
+
+		/**
+		 * Updates the local variable for the number of attributes the maximum
+		 * index (key) of the several hash maps.
+		 */
+		private void updateAttributeCount() {
+			// attribute names define the number of attributes, also
+			// if there are "more" normalize constraints specified
+			maxAttrIdx = LangUtil.max(attrNames.keySet(), normalizeAttr
+					.keySet(), noDataValues.keySet());
+
+			if (maxAttrCount > 0 && maxAttrIdx >= maxAttrCount)
+				throw new IllegalArgumentException("Only " + maxAttrCount
+						+ " attributes can be specified for "
+						+ LangUtil.getSimpleClassName(this));
+		}
+
+		/**
+		 * Removes all style informations about an attribute and reorganizes the
+		 * attribute indexes so there is an continuous order.
+		 * 
+		 * @param idx
+		 *            an attribute
+		 */
+		@Override
+		public void removeAttribute(int idx) {
+			// clear sets and maps of the removed attribute
+			Set<Object> noDataValues = getNoDataValues(idx);
+			if (noDataValues != null)
+				noDataValues.clear();
+
+			// remove the attribute by move the "greater" attributes
+			// one position "forward"
+			int maxIdx = getAttributeCount() - 1;
+			for (int i = idx; i < maxIdx; i++) {
+				this.attrNames.put(i, this.attrNames.get(i + 1));
+				this.normalizeAttr.put(i, this.normalizeAttr.get(i + 1));
+				this.noDataValues.put(i, this.noDataValues.get(i + 1));
+			}
+
+			// delete the last attribute, because now is is stored
+			// one position forward
+			this.attrNames.remove(maxIdx);
+			this.normalizeAttr.remove(maxIdx);
+			this.noDataValues.remove(maxIdx);
+
+			updateAttributeCount();
+		}
+
+		/**
+		 * Creates a (deep) clone of this style. The properties of the super
+		 * class ({@link AbstractChartStyle}) are <b>ignored</b> because they
+		 * are unused for the dummy.
+		 */
+		@Override
+		public AbstractChartStyle copy() {
+			return (AbstractChartStyle) copyTo((FeatureChartStyle) new Dummy(""));
+		}
+
+		/**
+		 * Copies all properties of this style to another one. The properties of
+		 * the super class ({@link AbstractChartStyle}) are <b>ignored</b>
+		 * because they are unused for the dummy.
+		 * 
+		 * @param dest
+		 *            destination object (if {@code null} the copy is created by
+		 *            {@link #copy()})
+		 * @return {@code dest} or the new instance
+		 */
+		@Override
+		public ChartStyle copyTo(ChartStyle dest) {
+			// !! do NOT copy the super class properties !!
+			// !! copy only this classes properties !!
+			// !! Reason: the dummy does not maintain the !!
+			// !! super class properties and we !!
+			// do not want to overwrite them !!
+			if (dest instanceof FeatureChartStyle) {
+				FeatureChartStyle destFCS = (FeatureChartStyle) dest;
+				destFCS.setSortDomainAxis(isSortDomainAxis());
+				destFCS.setForceCategories(isForceCategories());
+
+				// Clear the attribute names and attribute normalization
+				int max = destFCS.getMaxAttributeCount();
+				for (int i = 0; i < max; i++) {
+					destFCS.setAttributeName(i, null);
+					destFCS.setAttributeNormalized(i, null);
+
+					// Added by SK. In this special case we don't
+					destFCS.setNoDataValues(i, getNoDataValues(i));
+				}
+				// Copy attribute names and normalization
+				for (Integer idx : attrNames.keySet())
+					if (getAttributeName(idx) != null)
+						destFCS.setAttributeName(idx, getAttributeName(idx));
+				for (Integer idx : normalizeAttr.keySet())
+					if (isAttributeNormalized(idx))
+						destFCS.setAttributeNormalized(idx,
+								isAttributeNormalized(idx));
+
+			}
+
+			return dest;
+		}
+
+		/**
+		 * Returns the maximum number of feature attributes that can be
+		 * specified by this style.
+		 * 
+		 * @return -1 if there is no limit for range attributes
+		 */
+		@Override
+		public int getMaxAttributeCount() {
+			return maxAttrCount;
+		}
+
+		/**
+		 * Returns the number of feature attributes defined in this style.
+		 */
+		@Override
+		public int getAttributeCount() {
+			return maxAttrIdx + 1;
+		}
+
+		/**
+		 * Returns the name of a feature attribute needed to create a chart for
+		 * this style.
+		 * 
+		 * @param idx
+		 *            attribute index (0=domain; 1=1st range series; 2=2nd range
+		 *            series; ...)
+		 */
+		@Override
+		public String getAttributeName(int idx) {
+			return attrNames.get(idx);
+		}
+
+		/**
+		 * Sets the name of a feature attribute needed to create a chart for
+		 * this style.
+		 * 
+		 * @param idx
+		 *            attribute index (0=domain; 1=1st range series; 2=2nd range
+		 *            series; ...)
+		 * @param attrName
+		 *            feature attribute name
+		 */
+		@Override
+		public void setAttributeName(int idx, String attrName) {
+			attrNames.put(idx, attrName);
+			updateAttributeCount();
+		}
+
+		/**
+		 * Sets whether the features are sorted according to the domain
+		 * attribute (before creating a {@link Dataset}).
+		 */
+		@Override
+		public void setSortDomainAxis(boolean sortDomainAxis) {
+			this.sortDomainAxis = sortDomainAxis;
+		}
+
+		/**
+		 * Returns whether the features are sorted according to the domain
+		 * attribute (before creating a {@link Dataset}).
+		 * 
+		 * @return {@code false} as default
+		 */
+		@Override
+		public boolean isSortDomainAxis() {
+			return sortDomainAxis;
+		}
+
+		/**
+		 * Sets whether a {@link CategoryDataset} is forced for a numeric domain
+		 * attribute. The default is to create {@link XYDataset} for a numeric
+		 * and {@link CategoryDataset} for a non-numeric domain attribute.
+		 */
+		@Override
+		public void setForceCategories(boolean forceCategories) {
+			this.forceCategories = forceCategories;
+		}
+
+		/**
+		 * Returns whether a {@link CategoryDataset} is forced for a numeric
+		 * domain attribute. The default is to create {@link XYDataset} for a
+		 * numeric and {@link CategoryDataset} for a non-numeric domain
+		 * attribute.
+		 * 
+		 * @return {@code false} as default
+		 */
+		@Override
+		public boolean isForceCategories() {
+			return forceCategories;
+		}
+
+		/**
+		 * Sets whether the attribute data is normalized for an attribute
+		 * (before creating a {@link Dataset}).
+		 * 
+		 * @param idx
+		 *            attribute index (0=domain; 1=1st range series; 2=2nd range
+		 *            series; ...)
+		 * @param normalize
+		 *            indicates the normalize property
+		 */
+		@Override
+		public void setAttributeNormalized(int idx, Boolean normalize) {
+			normalizeAttr.put(idx, normalize);
+			updateAttributeCount();
+		}
+
+		/**
+		 * Returns whether the attribute data is normalized for an attribute
+		 * (before creating a {@link Dataset}).
+		 * 
+		 * @param idx
+		 *            attribute index (0=domain; 1=1st range series; 2=2nd range
+		 *            series; ...)
+		 * @return {@code false} as default
+		 */
+		@Override
+		public boolean isAttributeNormalized(int idx) {
+			Boolean normalize = normalizeAttr.get(idx);
+			return normalize != null && normalize;
+		}
+
+		/**
+		 * Sets an arithmetical function which is calculated on the attribute
+		 * values (when creating a {@link Dataset} from Features). The function
+		 * is calculated on all values with the same domain value (X/category).
+		 * If no function is set, duplicate domain values are ignored (only the
+		 * "last" value is shown, because of replacement behavior).
+		 * 
+		 * @param idx
+		 *            attribute index (1=1st range series; 2=2nd range series;
+		 *            ...)
+		 * @param func
+		 *            defines the calculated function
+		 * @exception IllegalArgumentException
+		 *                if function is set on domain attribute (0)
+		 */
+		@Override
+		public void setAttributeAggregation(int idx, AggregationFunction func) {
+			if (idx == 0)
+				throw new IllegalArgumentException(
+						"Aggregation function not allowed for attribute 0 (domain attribute)!");
+			aggrFuncs.put(idx, func);
+		}
+
+		/**
+		 * Returns an arithmetical function which is calculated on the attribute
+		 * values (when creating a {@link Dataset} from Features). The function
+		 * is calculated on all values with the same domain value (X/category).
+		 * If no function is set, duplicate domain values are ignored (only the
+		 * "last" value is shown, because of replacement behavior).
+		 * 
+		 * @param idx
+		 *            attribute index (1=1st range series; 2=2nd range series;
+		 *            ...)
+		 * @return {@code null} for index 0 (domain axis)
+		 */
+		@Override
+		public AggregationFunction getAttributeAggregation(int idx) {
+			if (idx == 0)
+				return null;
+			return aggrFuncs.get(idx);
+		}
+
+		/**
+		 * Sets the values, which are interpreted as "No Data".
+		 * 
+		 * @param idx
+		 *            attribute index the "No Data" values are set for
+		 * @param noDataValues
+		 *            the "No Data" values
+		 */
+		public void setNoDataValues(int idx, Set<Object> noDataValues) {
+			this.noDataValues.put(idx, noDataValues);
+			updateAttributeCount();
+		}
+
+		/**
+		 * Returns the values, which are interpreted as "No Data".
+		 * 
+		 * @param idx
+		 *            attribute index the "No Data" values are returned for
+		 */
+		public Set<Object> getNoDataValues(int idx) {
+			return this.noDataValues.get(idx);
+		}
+
+		/**
+		 * Sets a value, which is interpreted as "No Data".
+		 * 
+		 * @param idx
+		 *            attribute index the "No Data" value is set for
+		 * @param noDataValue
+		 *            the "No Data" value
+		 */
+		public void addNoDataValue(int idx, Object noDataValue) {
+			Set<Object> noDataValues = getNoDataValues(idx);
+			if (noDataValues == null) {
+				noDataValues = new HashSet<Object>();
+				setNoDataValues(idx, noDataValues);
+			}
+			noDataValues.add(noDataValue);
+		}
+
+		/**
+		 * Removes a "No Data" value for an attribute.
+		 * 
+		 * @param idx
+		 *            attribute index the "No Data" value is removed for
+		 * @param noDataValue
+		 *            the "No Data" value to remove
+		 * @return {@code false} if the value was not an "No Data" value
+		 */
+		public boolean removeNoDataValue(int idx, Object noDataValue) {
+			Set<Object> noDataValues = getNoDataValues(idx);
+			if (noDataValues == null)
+				return false;
+			return noDataValues.remove(noDataValue);
+		}
+
+		/**
+		 * Checks whether the given value is one of the "No data" values for the
+		 * attribute.
+		 * 
+		 * @param idx
+		 *            attribute index the "No Data" value is checked for
+		 * @param value
+		 *            an attribute value
+		 */
+		public boolean isNoDataValue(int idx, Object value) {
+			Set<Object> noDataValues = getNoDataValues(idx);
+			if (noDataValues == null)
+				return false;
+			return noDataValues.contains(value);
+		}
+
+		/**
+		 * Checks whether the given value is one of the "No data" values for the
+		 * attribute. In this case this method returns {@code null}, otherwise
+		 * the value itself.
+		 * 
+		 * @param idx
+		 *            attribute index the "No Data" value is checked for
+		 * @param value
+		 *            an attribute value
+		 * @return {@code null} if the given value is one of the "No data"
+		 *         values
+		 */
+		public <T> T filterNoDataValue(int idx, T value) {
+			if (isNoDataValue(idx, value))
+				return null;
+			return value;
+		}
+
+		/**
+		 * Does nothing, but always throws a
+		 * {@link UnsupportedOperationException}, because the dummy can not
+		 * provide this functionality.
+		 */
+		@Override
+		public JFreeChart applyToDataset(Dataset dataset) {
+			throw new UnsupportedOperationException(
+					"FeatureChartStyle.Dummy does not implement applyToDataset(..)");
+		}
+
+		/**
+		 * Does nothing, but always throws a
+		 * {@link UnsupportedOperationException}, because the dummy can not
+		 * provide this functionality.
+		 */
+		@Override
+		public JFreeChart applyToFeatureCollection(
+				FeatureCollection<SimpleFeatureType, SimpleFeature> fc) {
+			throw new UnsupportedOperationException(
+					"FeatureChartStyle.Dummy does not implement applyToFeatureCollection(..)");
+		}
+
+		/**
+		 * Updates the unitVisible parameter for all axes at once.
+		 * 
+		 * @param visible
+		 *            <code>true</code> if unit string shall be displayed in the
+		 *            chart.
+		 */
+		@Override
+		public void setUnitVisible(boolean visible) {
+			// TODO MArtin! Funktioniert so leider nicht. Warum ist hier
+			// getAxisCount() immer 0 ????
+			for (int axisIndex = 0; axisIndex < getAxisCount(); axisIndex++) {
+				getAxisStyle(axisIndex).setUnitVisible(visible);
+			}
+		}
+
 	}
 
-  }
-  
 }
-



More information about the Schmitzm-commits mailing list