[Schmitzm-commits] r815 - in trunk/src/schmitzm: jfree/feature/style xml

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Fri Apr 23 15:27:05 CEST 2010


Author: mojays
Date: 2010-04-23 15:27:03 +0200 (Fri, 23 Apr 2010)
New Revision: 815

Modified:
   trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java
   trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java
   trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java
   trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java
   trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java
   trunk/src/schmitzm/xml/XMLUtil.java
Log:
FeatureChartStyle extended with "series attribute", which is used to group the features to series.
Series attribute integrated in XML-ChartStyle.

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java	2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java	2010-04-23 13:27:03 UTC (rev 815)
@@ -29,6 +29,7 @@
  ******************************************************************************/
 package schmitzm.jfree.feature.style;
 
+import java.util.HashSet;
 import java.util.Set;
 
 import org.geotools.feature.FeatureCollection;
@@ -416,6 +417,88 @@
     }
 
     /**
+     * Defines the attribute whose values are used to define
+     * groups. For each group value a series is created in the chart
+     * dataset.
+     * @param attrName feature attribute name
+     */
+    @Override
+    public void setSeriesAttributeName(String attrName) {
+      dummyFeatureChartStyle.setSeriesAttributeName(attrName);
+    }
+    
+    /**
+     * Returns the attribute whose values are used to define
+     * groups. For each group value a series is created in the chart
+     * dataset.
+     */
+    @Override
+    public String getSeriesAttributeName() {
+      return dummyFeatureChartStyle.getSeriesAttributeName();
+    }
+
+    /**
+     * Sets the values, which are interpreted as "No Data" for the
+     * series attribute.
+     * @param noDataValues the "No Data" values
+     */
+    @Override
+    public void setSeriesAttributeNoDataValues(Set<Object> noDataValues) {
+      dummyFeatureChartStyle.setSeriesAttributeNoDataValues(noDataValues);
+    }
+
+    /**
+     * Returns the values, which are interpreted as "No Data" for the
+     * series attribute.
+     */
+    @Override
+    public Set<Object> getSeriesAttributeNoDataValues() {
+      return dummyFeatureChartStyle.getSeriesAttributeNoDataValues();
+    }
+
+    /**
+     * Sets a value, which is interpreted as "No Data" for the
+     * series attribute.
+     * @param noDataValue the "No Data" value
+     */
+    @Override
+    public void addSeriesAttributeNoDataValue(Object noDataValue) {
+      dummyFeatureChartStyle.addSeriesAttributeNoDataValue(noDataValue);
+    }
+
+    /**
+     * Removes a "No Data" value for the series attribute.
+     * @param noDataValue the "No Data" value to remove
+     * @return {@code false} if the value was not an "No Data" value
+     */
+    @Override
+   public boolean removeSeriesAttributeNoDataValue(Object noDataValue) {
+      return dummyFeatureChartStyle.removeSeriesAttributeNoDataValue(noDataValue);
+    }
+
+    /**
+     * Checks whether the given value is one of the "No data" values for the
+     * series attribute.
+     * @param value an attribute value
+     */
+    @Override
+    public boolean isSeriesAttributeNoDataValue(Object value) {
+      return dummyFeatureChartStyle.isSeriesAttributeNoDataValue(value);
+    }
+
+    /**
+     * Checks whether the given value is one of the "No data" values for the
+     * series attribute. In this case this method returns {@code null}, otherwise the
+     * value itself.
+     * @param value an attribute value
+     * @return {@code null} if the given value is one of the "No data" values
+     */
+    @Override
+    public <T> T filterSeriesAttributeNoDataValue(T value) {
+      return dummyFeatureChartStyle.filterSeriesAttributeNoDataValue(value);
+    }
+
+    /**
      * Creates an appropriate {@link Dataset} for the attributes defined
      * by this style (according to the attributes types in the given
      * {@link FeatureCollection}) and calls {@link #applyToDataset(Dataset)}.

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java	2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java	2010-04-23 13:27:03 UTC (rev 815)
@@ -277,7 +277,6 @@
    */
   public boolean isWeightAttributeNoDataValue(int idx, Object 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
@@ -289,6 +288,65 @@
   public <T> T filterWeightAttributeNoDataValue(int idx, T value);
 
   /**
+   * Defines the attribute whose values are used to define
+   * groups. For each group value a series is created in the chart
+   * dataset.
+   * @param attrName feature attribute name
+   */
+  public void setSeriesAttributeName(String attrName);
+  
+  /**
+   * Returns the attribute whose values are used to define
+   * groups. For each group value a series is created in the chart
+   * dataset.
+   */
+  public String getSeriesAttributeName();
+
+  /**
+   * Sets the values, which are interpreted as "No Data" for the
+   * series attribute.
+   * @param noDataValues the "No Data" values
+   */
+  public void setSeriesAttributeNoDataValues(Set<Object> noDataValues);
+
+  /**
+   * Returns the values, which are interpreted as "No Data" for the
+   * series attribute.
+   */
+  public Set<Object> getSeriesAttributeNoDataValues();
+
+  /**
+   * Sets a value, which is interpreted as "No Data" for the
+   * series attribute.
+   * @param noDataValue the "No Data" value
+   */
+  public void addSeriesAttributeNoDataValue(Object noDataValue);
+
+  /**
+   * Removes a "No Data" value for the series attribute.
+   * @param noDataValue the "No Data" value to remove
+   * @return {@code false} if the value was not an "No Data" value
+   */
+  public boolean removeSeriesAttributeNoDataValue(Object noDataValue);
+
+  /**
+   * Checks whether the given value is one of the "No data" values for the
+   * series attribute.
+   * @param value an attribute value
+   */
+  public boolean isSeriesAttributeNoDataValue(Object value);
+
+  /**
+   * Checks whether the given value is one of the "No data" values for the
+   * series attribute. In this case this method returns {@code null}, otherwise the
+   * value itself.
+   * @param value an attribute value
+   * @return {@code null} if the given value is one of the "No data" values
+   */
+  public <T> T filterSeriesAttributeNoDataValue(T value);
+
+
+  /**
    * Creates a chart according to the given
    * @param fc a feature collection
    * @exception UnsupportedOperationException if the style can not be applied to
@@ -364,7 +422,18 @@
     /** Holds the "No Data" values for each weight attribute. */
     protected Map<Integer, Set<Object>> weightAttrNoDataValues = new HashMap<Integer, Set<Object>>();
 
+    
     /**
+     * Holds the attribute name of the series attribute, whose values are
+     * used to define groups. For each group a series is created in the
+     * dataset.
+     */
+    protected String seriesAttrName = null;
+
+    /** Holds the "No Data" values for the series attribute. */
+    protected Set<Object> seriesAttrNoDataValues = new HashSet<Object>();
+
+    /**
      * 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.
@@ -845,6 +914,101 @@
     }
 
     /**
+     * Defines the attribute whose values are used to define
+     * groups. For each group value a series is created in the chart
+     * dataset.
+     * @param attrName feature attribute name
+     */
+    @Override
+    public void setSeriesAttributeName(String attrName) {
+      this.seriesAttrName = attrName;
+    }
+    
+    /**
+     * Returns the attribute whose values are used to define
+     * groups. For each group value a series is created in the chart
+     * dataset.
+     */
+    @Override
+    public String getSeriesAttributeName() {
+      return seriesAttrName;
+    }
+
+    /**
+     * Sets the values, which are interpreted as "No Data" for the
+     * series attribute.
+     * @param noDataValues the "No Data" values
+     */
+    @Override
+    public void setSeriesAttributeNoDataValues(Set<Object> noDataValues) {
+      seriesAttrNoDataValues = noDataValues;
+    }
+
+    /**
+     * Returns the values, which are interpreted as "No Data" for the
+     * series attribute.
+     */
+    @Override
+    public Set<Object> getSeriesAttributeNoDataValues() {
+      return this.seriesAttrNoDataValues;
+    }
+
+    /**
+     * Sets a value, which is interpreted as "No Data" for the
+     * series attribute.
+     * @param noDataValue the "No Data" value
+     */
+    @Override
+    public void addSeriesAttributeNoDataValue(Object noDataValue) {
+      Set<Object> noDataValues = getSeriesAttributeNoDataValues();
+      if (noDataValues == null) {
+        noDataValues = new HashSet<Object>();
+        setSeriesAttributeNoDataValues(noDataValues);
+      }
+      noDataValues.add(noDataValue);
+    }
+
+    /**
+     * Removes a "No Data" value for the series attribute.
+     * @param noDataValue the "No Data" value to remove
+     * @return {@code false} if the value was not an "No Data" value
+     */
+    @Override
+   public boolean removeSeriesAttributeNoDataValue(Object noDataValue) {
+      Set<Object> noDataValues = getSeriesAttributeNoDataValues();
+      if (noDataValues == null)
+        return false;
+      return noDataValues.remove(noDataValue);
+    }
+
+    /**
+     * Checks whether the given value is one of the "No data" values for the
+     * series attribute.
+     * @param value an attribute value
+     */
+    @Override
+    public boolean isSeriesAttributeNoDataValue(Object value) {
+      Set<Object> noDataValues = getSeriesAttributeNoDataValues();
+      if (noDataValues == null)
+        return false;
+      return noDataValues.contains(value);
+    }
+
+    /**
+     * Checks whether the given value is one of the "No data" values for the
+     * series attribute. In this case this method returns {@code null}, otherwise the
+     * value itself.
+     * @param value an attribute value
+     * @return {@code null} if the given value is one of the "No data" values
+     */
+    @Override
+    public <T> T filterSeriesAttributeNoDataValue(T value) {
+      if (isSeriesAttributeNoDataValue(value))
+        return null;
+      return value;
+    }
+
+    /**
      * Does nothing, but always throws a {@link UnsupportedOperationException},
      * because the dummy can not provide this functionality.
      */

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java	2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java	2010-04-23 13:27:03 UTC (rev 815)
@@ -29,7 +29,10 @@
  ******************************************************************************/
 package schmitzm.jfree.feature.style;
 
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
 
 import org.geotools.feature.FeatureCollection;
 import org.jdom.Element;
@@ -39,6 +42,7 @@
 import schmitzm.jfree.chart.style.ChartStyleXMLFactory;
 import schmitzm.jfree.chart.style.ChartType;
 import schmitzm.jfree.feature.AggregationFunction;
+import schmitzm.lang.LangUtil;
 import schmitzm.xml.XMLUtil;
 
 /**
@@ -85,23 +89,41 @@
     chartStyle.setAttributeNormalized(0, XMLUtil.getBooleanAttribute(domainAttrElem, "normalize", false));
     chartStyle.setSortDomainAxis(XMLUtil.getBooleanAttribute(domainAttrElem, "sort", false));
     chartStyle.setForceCategories(XMLUtil.getBooleanAttribute(domainAttrElem, "forceCategories", false));
+    Set<Object> nullAliases = XMLUtil.getSetAttribute(domainAttrElem, "nullAliases");
+    if (nullAliases != null)
+      chartStyle.setNoDataValues(0, nullAliases);
     
     // Read all range attribute definitions
     int rangeAttrNo = 0;
-    for (Element featureAttrElem : (List<Element>)featureElement.getChildren("rangeAttr") ) {
-      String featureAttrName = XMLUtil.getAttribute(featureAttrElem, "name");
+    for (Element rangeAttrElem : (List<Element>)featureElement.getChildren("rangeAttr") ) {
+      String featureAttrName = XMLUtil.getAttribute(rangeAttrElem, "name");
       if ( featureAttrName == null )
         throw new UnsupportedOperationException("Attribute 'name' necessary for <rangeAttr> element of FeatureChartStyle!");
       // Apply attributes to style
       rangeAttrNo++;
       chartStyle.setAttributeName(rangeAttrNo, featureAttrName);
-      chartStyle.setAttributeNormalized(rangeAttrNo, XMLUtil.getBooleanAttribute(domainAttrElem, "normalize", false));
-      String aggrFuncStr = XMLUtil.getAttribute(domainAttrElem, "function", (String)null);
+      chartStyle.setAttributeNormalized(rangeAttrNo, XMLUtil.getBooleanAttribute(rangeAttrElem, "normalize", false));
+      String aggrFuncStr = XMLUtil.getAttribute(rangeAttrElem, "function", (String)null);
       if ( aggrFuncStr != null )
         chartStyle.setAttributeAggregation(rangeAttrNo, AggregationFunction.valueOf(aggrFuncStr) );
+      nullAliases = XMLUtil.getSetAttribute(rangeAttrElem, "nullAliases");
+      if (nullAliases != null)
+        chartStyle.setNoDataValues(rangeAttrNo, nullAliases);
     }
-  }
 
+    // Read (optional) series attribute (its values defines the series groups)
+    Element seriesAttrElem = featureElement.getChild("seriesAttr");
+    if ( seriesAttrElem != null ) {
+      String seriesAttrName = XMLUtil.getAttribute(seriesAttrElem, "name");
+      if ( seriesAttrName == null )
+        throw new UnsupportedOperationException("Attribute 'name' necessary for <seriesAttr> element of FeatureChartStyle!");
+      chartStyle.setSeriesAttributeName(seriesAttrName);
+      nullAliases = XMLUtil.getSetAttribute(seriesAttrElem, "nullAliases");
+      if (nullAliases != null)
+        chartStyle.setSeriesAttributeNoDataValues(nullAliases);
+    }
+}
+
   /**
    * Creates a default style for a chart type.
    * @param id   a (unique) ID for the style
@@ -139,6 +161,7 @@
       addChildToElement(attrElem, "domainAttr", false,
           "name", style.getAttributeName(0),
           "normalize", style.isAttributeNormalized(0),
+          "nullAliases", XMLUtil.convertSetToSeparatedString(style.getSeriesAttributeNoDataValues()), 
           "sort", style.isSortDomainAxis(),
           "forceCategories", style.isForceCategories()
       );
@@ -148,9 +171,17 @@
       addChildToElement(attrElem, "rangeAttr", false,
           "name", style.getAttributeName(i),
           "normalize", style.isAttributeNormalized(i),
+          "nullAliases", XMLUtil.convertSetToSeparatedString(style.getNoDataValues(i)), 
           "function", style.getAttributeAggregation(i)
       );
 
+    // Series attribute definition
+    if ( style.getSeriesAttributeName() != null )
+      addChildToElement(attrElem, "seriesAttr", false,
+          "name", style.getSeriesAttributeName(),
+          "nullAliases", XMLUtil.convertSetToSeparatedString(style.getSeriesAttributeNoDataValues()) 
+      );
+
     return root;
   }
 }

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java	2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java	2010-04-23 13:27:03 UTC (rev 815)
@@ -657,7 +657,16 @@
                                                 catValue);
         if (catValue == null)
           continue;
-
+        
+        // If grouping series attribute is used, filter out
+        // its no data values
+        Object seriesID = null;
+        if ( chartStyle.getSeriesAttributeName() != null ) {
+          seriesID = determineSeriesAttributeValueFromFeature(f, chartStyle);
+          if ( seriesID == null )
+            continue;
+        }
+        
         // Determine the Y values and fill the dataset
         for (int attrIdx = 1; attrIdx < attrCount; attrIdx++) {
           Double yValue = determineRangeValueFromFeature(
@@ -676,6 +685,10 @@
           if (chartStyle.getAttributeAggregation(attrIdx) == null) {
             // Add data to dataset
             String yAttrName = chartStyle.getAttributeName(attrIdx);
+            // If grouping series attribute is used, add its value
+            // to the series ID
+            if ( seriesID != null )
+              yAttrName = yAttrName + "_" + seriesID.toString();
             dataset.addValue(yValue, yAttrName, catValue);
             // Mapping between FID and data index in series
             mapping.setMapping(f.getID(), yAttrName, catValue);
@@ -906,7 +919,25 @@
     return yValue.doubleValue();
   }
 
+
   /**
+   * Determines the value from the series attribute of a feature and transforms it
+   * according to the (optional) no data values.
+   * @param feature a feature
+   * @param chartStyle the chart style
+   * @return {@code null} if the feature must be ignored because of an invalid
+   *         (null) value
+   */
+  private static Object determineSeriesAttributeValueFromFeature(SimpleFeature feature,
+      FeatureChartStyle chartStyle) {
+    String seriesAttrName  = chartStyle.getSeriesAttributeName();
+    Object seriesAttrValue = feature.getAttribute(seriesAttrName);
+    // Filter out NoDataValues
+    seriesAttrValue = chartStyle.filterSeriesAttributeNoDataValue(seriesAttrValue);
+    return seriesAttrValue;
+  }
+
+  /**
    * Transforms
    * @param func
    * @param value

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java	2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java	2010-04-23 13:27:03 UTC (rev 815)
@@ -429,6 +429,88 @@
   }
 
   /**
+   * Defines the attribute whose values are used to define
+   * groups. For each group value a series is created in the chart
+   * dataset.
+   * @param attrName feature attribute name
+   */
+  @Override
+  public void setSeriesAttributeName(String attrName) {
+    dummyFeatureChartStyle.setSeriesAttributeName(attrName);
+  }
+  
+  /**
+   * Returns the attribute whose values are used to define
+   * groups. For each group value a series is created in the chart
+   * dataset.
+   */
+  @Override
+  public String getSeriesAttributeName() {
+    return dummyFeatureChartStyle.getSeriesAttributeName();
+  }
+
+  /**
+   * Sets the values, which are interpreted as "No Data" for the
+   * series attribute.
+   * @param noDataValues the "No Data" values
+   */
+  @Override
+  public void setSeriesAttributeNoDataValues(Set<Object> noDataValues) {
+    dummyFeatureChartStyle.setSeriesAttributeNoDataValues(noDataValues);
+  }
+
+  /**
+   * Returns the values, which are interpreted as "No Data" for the
+   * series attribute.
+   */
+  @Override
+  public Set<Object> getSeriesAttributeNoDataValues() {
+    return dummyFeatureChartStyle.getSeriesAttributeNoDataValues();
+  }
+
+  /**
+   * Sets a value, which is interpreted as "No Data" for the
+   * series attribute.
+   * @param noDataValue the "No Data" value
+   */
+  @Override
+  public void addSeriesAttributeNoDataValue(Object noDataValue) {
+    dummyFeatureChartStyle.addSeriesAttributeNoDataValue(noDataValue);
+  }
+
+  /**
+   * Removes a "No Data" value for the series attribute.
+   * @param noDataValue the "No Data" value to remove
+   * @return {@code false} if the value was not an "No Data" value
+   */
+  @Override
+ public boolean removeSeriesAttributeNoDataValue(Object noDataValue) {
+    return dummyFeatureChartStyle.removeSeriesAttributeNoDataValue(noDataValue);
+  }
+
+  /**
+   * Checks whether the given value is one of the "No data" values for the
+   * series attribute.
+   * @param value an attribute value
+   */
+  @Override
+  public boolean isSeriesAttributeNoDataValue(Object value) {
+    return dummyFeatureChartStyle.isSeriesAttributeNoDataValue(value);
+  }
+
+  /**
+   * Checks whether the given value is one of the "No data" values for the
+   * series attribute. In this case this method returns {@code null}, otherwise the
+   * value itself.
+   * @param value an attribute value
+   * @return {@code null} if the given value is one of the "No data" values
+   */
+  @Override
+  public <T> T filterSeriesAttributeNoDataValue(T value) {
+    return dummyFeatureChartStyle.filterSeriesAttributeNoDataValue(value);
+  }
+
+  /**
    * Creates an appropriate {@link Dataset} for the attributes defined
    * by this style (according to the attributes types in the given
    * {@link FeatureCollection}) and calls {@link #applyToDataset(Dataset)}.

Modified: trunk/src/schmitzm/xml/XMLUtil.java
===================================================================
--- trunk/src/schmitzm/xml/XMLUtil.java	2010-04-23 13:17:35 UTC (rev 814)
+++ trunk/src/schmitzm/xml/XMLUtil.java	2010-04-23 13:27:03 UTC (rev 815)
@@ -30,6 +30,9 @@
 package schmitzm.xml;
 
 import java.awt.Color;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
 
 import org.apache.log4j.Logger;
 import org.jdom.Element;
@@ -37,6 +40,7 @@
 import org.jdom.output.Format;
 import org.jdom.output.XMLOutputter;
 
+import schmitzm.lang.LangUtil;
 import schmitzm.swing.SwingUtil;
 import skrueger.i8n.Translation;
 
@@ -156,8 +160,52 @@
       return defValue[0];
     return null;
   }
+  
+  /**
+   * Gets a string-separated attribute value from element as {@code Set<String>}.
+   * @param element  element where the attribute is determined from
+   * @param attrName name of the attribute
+   * @param defValue optional default value returned if attribute is not found (or empty)
+   * @return {@code null} if {@code element} is {@code null} or attribute is not
+   *         specified in element
+   */
+  public static Set<Object> getSetAttribute(Element element, String attrName, Set<Object>... defValue) {
+    String value = getAttribute(element, attrName);
+    if ( value != null )
+      return convertSeparatedStringToSet(value);
+    if ( defValue.length > 0 )
+      return defValue[0];
+    return null;
+  }
 
   /**
+   * Parses a semicolon-separated string and stores its elements in
+   * a set. 
+   * @param objectString the semicolon-separated string of objects
+   * @return an empty set if the string is empty
+   */
+  public static Set<Object> convertSeparatedStringToSet(String objectString) {
+    Set<Object>     objects = new HashSet<Object>();
+    StringTokenizer st      = new StringTokenizer(objectString,";\n");
+    for (;st.hasMoreTokens();)
+      objects.add( st.nextToken() );
+    return objects; 
+  }
+
+  /**
+   * Creates a semicolon-separated string of the elements of a set. 
+   * @param objects the objects which are transformed to string and
+   *                concatenated
+   * @return {@code null} if the set is empty or {@code null}
+   */
+  public static String convertSetToSeparatedString(Set<Object> objects) {
+    if ( objects == null || objects.isEmpty() )
+      return null;
+    return LangUtil.stringConcatWithSep(";", objects.toArray()); 
+  }
+
+
+  /**
    * Sets an attribute value. The {@code .toString()} method is used
    * to convert the object value to string.<br>
    * Exceptions:



More information about the Schmitzm-commits mailing list