/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2009-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2009-2012, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotoolkit.image.io.metadata; import javax.imageio.metadata.IIOMetadataFormat; import org.apache.sis.util.CharSequences; import org.apache.sis.measure.NumberRange; import org.geotoolkit.util.collection.XCollections; import org.geotoolkit.metadata.ValueRestriction; /** * The values that are valid for a given element or attribute. A {@code ValidValue} * may describe a range or an enumeration. Instances of this class are used by * {@link MetadataTreeNode} only. * * @author Martin Desruisseaux (Geomatys) * @version 3.05 * * @since 3.04 * @module */ final class ValidValues extends ValueRestriction { /** * For cross-version compatibility. */ private static final long serialVersionUID = -148744234616697972L; /** * Placeholder meaning that we have determined that there is no restriction on valid values. */ static final ValidValues UNRESTRICTED = new ValidValues(); /** * The constructor for the {@link #UNRESTRICTED} singleton. */ private ValidValues() { super(null, null, null); } /** * Creates a new {@code ValidValues} instance for the given enumeration. */ ValidValues(final Object[] values) { super(null, null, XCollections.immutableSet(values)); } /** * Creates a new {@code ValidValues} for a range with the given type, minimum and maximum * values. The inclusion status of minimum and maximum values are inferred from the given * {@code rangeType} argument. * <p> * Do no use this constructor directly; use one of the {@code range(...)} method instead. * * @param <T> The type of elements in the range. * @param type The type of elements in the range. * @param rangeType One of {@code IIOMetadataFormat.VALUE_RANGE_*} constants. * @param min The minimal value. * @param max The maximal value. */ private <T extends Number & Comparable<? super T>> ValidValues( final Class<T> type, final int rangeType, final T min, final T max) { super(null, new NumberRange<>(type, min, (rangeType & IIOMetadataFormat.VALUE_RANGE_MIN_INCLUSIVE_MASK) != 0, max, (rangeType & IIOMetadataFormat.VALUE_RANGE_MAX_INCLUSIVE_MASK) != 0), null); } /** * Casts the given minimum and maximum values to the expected type and invoke {@link #create}. * This is an helper method for playing with parameterized type. */ private static <T extends Number & Comparable<? super T>> ValidValues cast(final Class<T> type, final int rangeType, final Comparable<?> min, final Comparable<?> max) { return new ValidValues(type, rangeType, type.cast(min), type.cast(max)); } /** * Creates a new {@code ValidValue} for a range with the given type, minimum and maximum * values. The inclusion status of minimum and maximum values are inferred from the given * {@code rangeType} argument. * * @param <T> The type of elements in the range. * @param type The type of elements in the range. * @param rangeType One of {@code IIOMetadataFormat.VALUE_RANGE_*} constants. * @param min The minimal value. * @param max The maximal value. * @return The range. */ @SuppressWarnings({"unchecked","rawtypes"}) static ValidValues range(final Class<?> type, final int rangeType, final Comparable<?> min, final Comparable<?> max) { if (Number.class.isAssignableFrom(type) && Comparable.class.isAssignableFrom(type)) { return cast((Class) type, rangeType, min, max); } return UNRESTRICTED; } /** * Creates a new instance for the given attribute range. Note that in the particular case * of node attributes, the range values are always represented as {@link String} even if * the underlying type is a number. * * @param datatype One of {@code IIOMetadataFormat.DATATYPE_*} constants. * @param rangeType One of {@code IIOMetadataFormat.VALUE_RANGE_*} constants. * @param min The minimal value. * @param max The maximal value. * @return The range of values, or {@link #UNRESTRICTED} if the given type is not supported. * @throws NumberFormatException If a string can not be parsed as a number of the given type. */ static ValidValues range(final int datatype, final int rangeType, final String min, final String max) { switch (datatype) { case IIOMetadataFormat.DATATYPE_DOUBLE: { return new ValidValues(Double.class, rangeType, (min == null) ? null : Double.valueOf(min), (max == null) ? null : Double.valueOf(max)); } case IIOMetadataFormat.DATATYPE_FLOAT: { return new ValidValues(Float.class, rangeType, (min == null) ? null : Float.valueOf(min), (max == null) ? null : Float.valueOf(max)); } case IIOMetadataFormat.DATATYPE_INTEGER: { return new ValidValues(Integer.class, rangeType, (min == null) ? null : Integer.valueOf(min), (max == null) ? null : Integer.valueOf(max)); } default: { return UNRESTRICTED; } } } /** * Returns a string representation of this {@code ValidValues} to be used in widgets. * In the {@link #UNRESTRICTED} case, returns an empty string meaning "no restriction". */ @Override public String toString() { if (validValues != null) { final StringBuilder buffer = new StringBuilder(); for (final Object code : validValues) { if (buffer.length() != 0) { buffer.append(", "); } buffer.append(CharSequences.camelCaseToWords(code.toString(), true)); } return buffer.toString(); } return (range != null) ? range.toString() : ""; } }