Search in sources :

Example 21 with GenericName

use of org.opengis.util.GenericName in project sis by apache.

the class IdentifiedObjects method getUnicodeIdentifier.

/**
 * Returns the first name, alias or identifier which is a
 * {@linkplain CharSequences#isUnicodeIdentifier(CharSequence) valid Unicode identifier}.
 * This method performs the search in the following order:
 *
 * <ul>
 *   <li><code>object.{@linkplain AbstractIdentifiedObject#getName() getName()}</code></li>
 *   <li><code>object.{@linkplain AbstractIdentifiedObject#getAlias() getAlias()}</code> in iteration order</li>
 *   <li><code>object.{@linkplain AbstractIdentifiedObject#getIdentifiers() getIdentifiers()}</code> in iteration order</li>
 * </ul>
 *
 * @param  object  the identified object, or {@code null}.
 * @return the first name, alias or identifier which is a valid Unicode identifier, or {@code null} if none.
 *
 * @see org.apache.sis.metadata.iso.ImmutableIdentifier
 * @see org.apache.sis.metadata.iso.citation.Citations#getUnicodeIdentifier(Citation)
 * @see org.apache.sis.util.CharSequences#isUnicodeIdentifier(CharSequence)
 */
public static String getUnicodeIdentifier(final IdentifiedObject object) {
    if (object != null) {
        Identifier identifier = object.getName();
        if (identifier != null) {
            // Paranoiac check.
            final String code = identifier.getCode();
            if (CharSequences.isUnicodeIdentifier(code)) {
                return code;
            }
        }
        final Iterator<GenericName> it = iterator(object.getAlias());
        if (it != null)
            while (it.hasNext()) {
                GenericName alias = it.next();
                if (alias != null && (alias = alias.tip()) != null) {
                    final String code = alias.toString();
                    if (CharSequences.isUnicodeIdentifier(code)) {
                        return code;
                    }
                }
            }
        final Iterator<? extends Identifier> id = iterator(object.getIdentifiers());
        if (id != null)
            while (id.hasNext()) {
                identifier = id.next();
                if (identifier != null) {
                    // Paranoiac check.
                    final String code = identifier.getCode();
                    if (CharSequences.isUnicodeIdentifier(code)) {
                        return code;
                    }
                }
            }
    }
    return null;
}
Also used : GenericName(org.opengis.util.GenericName) NameToIdentifier(org.apache.sis.internal.metadata.NameToIdentifier) Identifier(org.opengis.metadata.Identifier) ReferenceIdentifier(org.opengis.referencing.ReferenceIdentifier)

Example 22 with GenericName

use of org.opengis.util.GenericName in project sis by apache.

the class ParameterFormat method formatSummary.

/**
 * Implementation of public {@code format(…)} methods for {@code NAME_SUMMARY} content level.
 *
 * @param  objects  the collection of objects to format.
 * @param  out      the stream or buffer where to write the summary.
 * @throws IOException if an error occurred will writing to the given appendable.
 */
private void formatSummary(final IdentifiedObject[] objects, final Appendable out) throws IOException {
    final Vocabulary resources = Vocabulary.getResources(displayLocale);
    /*
         * Prepares all rows before we write them to the output stream, because not all
         * identified objects may have names with the same scopes in the same order. We
         * also need to iterate over all rows in order to know the number of columns.
         *
         * The first column is reserved for the identifier. We put null as a sentinal key for
         * that column name, to be replaced later by "Identifier" in user locale. We can not
         * put the localized strings in the map right now because they could conflict with
         * the scope of some alias to be processed below.
         */
    boolean hasIdentifiers = false;
    final List<String[]> rows = new ArrayList<>();
    final Map<String, Integer> columnIndices = new LinkedHashMap<>();
    // See above comment for the meaning of "null" here.
    columnIndices.put(null, 0);
    if (preferredCodespaces != null) {
        for (final String codespace : preferredCodespaces) {
            columnIndices.put(codespace, columnIndices.size());
        }
    }
    for (final IdentifiedObject object : objects) {
        // Will growth later if needed.
        String[] row = new String[columnIndices.size()];
        /*
             * Put the first identifier in the first column. If no identifier has a codespace in the list
             * supplied by the user, then we will use the first identifier (any codespace) as a fallback.
             */
        final Set<ReferenceIdentifier> identifiers = object.getIdentifiers();
        if (identifiers != null) {
            // Paranoiac check.
            Identifier identifier = null;
            for (final ReferenceIdentifier candidate : identifiers) {
                if (candidate != null) {
                    // Paranoiac check.
                    if (isPreferredCodespace(candidate.getCodeSpace())) {
                        identifier = candidate;
                        // Format now.
                        break;
                    }
                    if (identifier == null) {
                        // To be used as a fallback if we find nothing better.
                        identifier = candidate;
                    }
                }
            }
            if (identifier != null) {
                row[0] = IdentifiedObjects.toString(identifier);
                hasIdentifiers = true;
            }
        }
        /*
             * If the name's codespace is in the list of codespaces asked by the user, add that name
             * in the current row and clear the 'name' locale variable. Otherwise, keep the 'name'
             * locale variable in case we found no alias to format.
             */
        ReferenceIdentifier name = object.getName();
        if (name != null) {
            // Paranoiac check.
            final String codespace = name.getCodeSpace();
            if (isPreferredCodespace(codespace)) {
                row = putIfAbsent(resources, row, columnIndices, codespace, name.getCode());
                name = null;
            }
        }
        /*
             * Put all aliases having a codespace in the list asked by the user.
             */
        final Collection<GenericName> aliases = object.getAlias();
        if (aliases != null) {
            // Paranoiac check.
            for (final GenericName alias : aliases) {
                if (alias != null) {
                    // Paranoiac check.
                    final String codespace = NameToIdentifier.getCodeSpace(alias, displayLocale);
                    if (isPreferredCodespace(codespace)) {
                        row = putIfAbsent(resources, row, columnIndices, codespace, alias.tip().toInternationalString().toString(displayLocale));
                        name = null;
                    }
                }
            }
        }
        /*
             * If no name and no alias have a codespace in the list of codespaces asked by the user,
             * force the addition of primary name regardless its codespace.
             */
        if (name != null) {
            row = putIfAbsent(resources, row, columnIndices, name.getCodeSpace(), name.getCode());
        }
        rows.add(row);
    }
    /*
         * Writes the table. The header will contain one column for each codespace in the order declared
         * by the user. If the user did not specified any codespace, or if we had to write codespace not
         * on the user list, then those codespaces will be written in the order we found them.
         */
    final boolean hasColors = (colors != null);
    final TableAppender table = new TableAppender(out, columnSeparator);
    table.setMultiLinesCells(true);
    table.appendHorizontalSeparator();
    for (String codespace : columnIndices.keySet()) {
        if (codespace == null) {
            // Skip empty column.
            if (!hasIdentifiers)
                continue;
            codespace = resources.getString(Vocabulary.Keys.Identifier);
        }
        if (hasColors) {
            codespace = X364.BOLD.sequence() + codespace + X364.NORMAL.sequence();
        }
        table.append(codespace);
        nextColumn(table);
    }
    table.appendHorizontalSeparator();
    /*
         * Writes row content.
         */
    final int numColumns = columnIndices.size();
    for (final String[] row : rows) {
        for (int i = hasIdentifiers ? 0 : 1; i < numColumns; i++) {
            if (i < row.length) {
                final String name = row[i];
                if (name != null) {
                    table.append(name);
                }
            }
            nextColumn(table);
        }
        table.nextLine();
    }
    table.appendHorizontalSeparator();
    table.flush();
}
Also used : Vocabulary(org.apache.sis.util.resources.Vocabulary) ArrayList(java.util.ArrayList) TableAppender(org.apache.sis.io.TableAppender) LinkedHashMap(java.util.LinkedHashMap) GenericName(org.opengis.util.GenericName) ReferenceIdentifier(org.opengis.referencing.ReferenceIdentifier) NameToIdentifier(org.apache.sis.internal.metadata.NameToIdentifier) Identifier(org.opengis.metadata.Identifier) ReferenceIdentifier(org.opengis.referencing.ReferenceIdentifier) IdentifiedObject(org.opengis.referencing.IdentifiedObject)

Example 23 with GenericName

use of org.opengis.util.GenericName in project sis by apache.

the class MatrixParametersAlphaNum method createElementDescriptor.

/**
 * Creates a new parameter descriptor for a matrix element at the given indices. This method creates both the
 * OGC name (e.g. {@code "elt_1_2"}) and the EPSG name (e.g. {@code "B2"}), together with the EPSG identifier
 * (e.g. {@code "EPSG:8641"}) if it exists. See {@link org.apache.sis.internal.referencing.provider.Affine}
 * for a table summarizing the parameter names and identifiers.
 */
@Override
protected ParameterDescriptor<Double> createElementDescriptor(final int[] indices) throws IllegalArgumentException {
    /*
         * For the EPSG convention, we recycle the names created for the WKT1 convention but interchanging
         * the name with the alias (since our WKT1 convention adds the EPSG names as aliases). We use WKT1
         * as the primary source because it is still very widely used,  and works for arbitrary dimensions
         * while the EPSG parameters are (officially) restricted to 3×3 matrices.
         */
    if (WKT1 == this) {
        /*
             * Should never happen, but still unconditionally tested
             * (no 'assert' keyword) for preventing stack overflow.
             */
        throw new AssertionError();
    }
    // Really 'WKT1', not 'super'.
    final ParameterDescriptor<Double> wkt = WKT1.getElementDescriptor(indices);
    GenericName name = first(wkt.getAlias());
    if (name == null) {
        /*
             * Outside the range of names (e.g. more than 26 rows or more than 10 columns).
             * Returns the OGC name as-is.
             */
        return wkt;
    }
    final Map<String, Object> properties = new HashMap<>(6);
    /*
         * Declare the EPSG identifier only for A0, A1, A2, B0, B1 and B2.
         */
    if (isEPSG(indices)) {
        // Put the name in EPSG namespace.
        name = EPSGName.create(name.tip().toString());
        final int code = (indices[0] == 0 ? Constants.EPSG_A0 : Constants.EPSG_B0) + indices[1];
        properties.put(ParameterDescriptor.IDENTIFIERS_KEY, EPSGName.identifier(code));
    }
    properties.put(ParameterDescriptor.NAME_KEY, name);
    properties.put(ParameterDescriptor.ALIAS_KEY, wkt.getName());
    return new DefaultParameterDescriptor<>(properties, 0, 1, Double.class, null, null, wkt.getDefaultValue());
}
Also used : GenericName(org.opengis.util.GenericName) HashMap(java.util.HashMap)

Example 24 with GenericName

use of org.opengis.util.GenericName in project sis by apache.

the class CoordinateOperationMethods method getDomainOfValidity.

/**
 * Returns the domain of validity for the given operation method.
 * If no domain of validity is found, returns {@code null}.
 */
private DefaultGeographicBoundingBox getDomainOfValidity(final OperationMethod method) {
    DefaultGeographicBoundingBox validity = null;
    for (final GenericName name : method.getAlias()) {
        final String tip = name.tip().toString();
        final DefaultGeographicBoundingBox candidate = domainOfValidity.get(tip);
        if (candidate != null) {
            if (validity == null) {
                validity = new DefaultGeographicBoundingBox(candidate);
            } else {
                validity.add(candidate);
            }
        }
    }
    return validity;
}
Also used : GenericName(org.opengis.util.GenericName) DefaultGeographicBoundingBox(org.apache.sis.metadata.iso.extent.DefaultGeographicBoundingBox)

Example 25 with GenericName

use of org.opengis.util.GenericName in project sis by apache.

the class FeatureFormat method format.

/**
 * Formats the given object to the given stream of buffer.
 * The object may be an instance of any of the following types:
 *
 * <ul>
 *   <li>{@code Feature}</li>
 *   <li>{@code FeatureType}</li>
 * </ul>
 *
 * @throws IOException if an error occurred while writing to the given appendable.
 */
@Override
public void format(final Object object, final Appendable toAppendTo) throws IOException {
    ArgumentChecks.ensureNonNull("object", object);
    ArgumentChecks.ensureNonNull("toAppendTo", toAppendTo);
    /*
         * Separate the Feature (optional) and the FeatureType (mandatory) instances.
         */
    final DefaultFeatureType featureType;
    final AbstractFeature feature;
    if (object instanceof AbstractFeature) {
        feature = (AbstractFeature) object;
        featureType = feature.getType();
    } else if (object instanceof DefaultFeatureType) {
        featureType = (DefaultFeatureType) object;
        feature = null;
    } else {
        throw new IllegalArgumentException(Errors.getResources(displayLocale).getString(Errors.Keys.UnsupportedType_1, object.getClass()));
    }
    /*
         * Computes the columns to show. We start with the set of columns specified by setAllowedColumns(Set),
         * then we check if some of those columns are empty. For example in many cases there is no attribute
         * with characteritic, in which case we will ommit the whole "characteristics" column. We perform such
         * check only for optional information, not for mandatory information like property names.
         */
    final EnumSet<Column> visibleColumns = columns.clone();
    {
        boolean hasDesignation = false;
        boolean hasCharacteristics = false;
        boolean hasDeprecatedTypes = false;
        for (final AbstractIdentifiedType propertyType : featureType.getProperties(true)) {
            if (!hasDesignation) {
                hasDesignation = propertyType.getDesignation() != null;
            }
            if (!hasCharacteristics && propertyType instanceof DefaultAttributeType<?>) {
                hasCharacteristics = !((DefaultAttributeType<?>) propertyType).characteristics().isEmpty();
            }
            if (!hasDeprecatedTypes && propertyType instanceof Deprecable) {
                hasDeprecatedTypes = ((Deprecable) propertyType).isDeprecated();
            }
        }
        if (!hasDesignation)
            visibleColumns.remove(Column.DESIGNATION);
        if (!hasCharacteristics)
            visibleColumns.remove(Column.CHARACTERISTICS);
        if (!hasDeprecatedTypes)
            visibleColumns.remove(Column.REMARKS);
    }
    /*
         * Format the feature type name. In the case of feature type, format also the names of super-type
         * after the UML symbol for inheritance (an arrow with white head). We do not use the " : " ASCII
         * character for avoiding confusion with the ":" separator in namespaces. After the feature (type)
         * name, format the column header: property name, type, cardinality and (default) value.
         */
    toAppendTo.append(toString(featureType.getName()));
    if (feature == null) {
        // UML symbol for inheritance.
        String separator = " ⇾ ";
        for (final FeatureType parent : featureType.getSuperTypes()) {
            toAppendTo.append(separator).append(toString(parent.getName()));
            separator = SEPARATOR;
        }
    }
    toAppendTo.append(getLineSeparator());
    /*
         * Create a table and format the header. Columns will be shown in Column enumeration order.
         */
    final Vocabulary resources = Vocabulary.getResources(displayLocale);
    final TableAppender table = new TableAppender(toAppendTo, columnSeparator);
    table.setMultiLinesCells(true);
    table.nextLine('─');
    boolean isFirstColumn = true;
    for (final Column column : visibleColumns) {
        short key = column.resourceKey;
        if (key == Vocabulary.Keys.Value && feature == null) {
            key = Vocabulary.Keys.DefaultValue;
        }
        if (!isFirstColumn)
            nextColumn(table);
        table.append(resources.getString(key));
        isFirstColumn = false;
    }
    table.nextLine();
    table.nextLine('─');
    /*
         * Done writing the header. Now write all property rows.  For each row, the first part in the loop
         * extracts all information needed without formatting anything yet. If we detect in that part that
         * a row has no value, it will be skipped if and only if that row is optional (minimum occurrence
         * of zero).
         */
    final StringBuffer buffer = new StringBuffer();
    final FieldPosition dummyFP = new FieldPosition(-1);
    final List<String> remarks = new ArrayList<>();
    for (final AbstractIdentifiedType propertyType : featureType.getProperties(true)) {
        Object value = null;
        int cardinality = -1;
        if (feature != null) {
            if (!(propertyType instanceof DefaultAttributeType<?>) && !(propertyType instanceof DefaultAssociationRole) && !DefaultFeatureType.isParameterlessOperation(propertyType)) {
                continue;
            }
            value = feature.getPropertyValue(propertyType.getName().toString());
            if (value == null) {
                if (propertyType instanceof FieldType && ((FieldType) propertyType).getMinimumOccurs() == 0) {
                    // If optional and no value, skip the full row.
                    continue;
                }
                cardinality = 0;
            } else if (value instanceof Collection<?>) {
                cardinality = ((Collection<?>) value).size();
            } else {
                cardinality = 1;
            }
        } else if (propertyType instanceof DefaultAttributeType<?>) {
            value = ((DefaultAttributeType<?>) propertyType).getDefaultValue();
        } else if (propertyType instanceof AbstractOperation) {
            buffer.append(" = ");
            try {
                ((AbstractOperation) propertyType).formatResultFormula(buffer);
            } catch (IOException e) {
                // Should never happen since we write in a StringBuffer.
                throw new UncheckedIOException(e);
            }
            value = CharSequences.trimWhitespaces(buffer).toString();
            buffer.setLength(0);
        }
        // The value to write in the type column.
        final String valueType;
        // AttributeType.getValueClass() if applicable.
        final Class<?> valueClass;
        // Negative values mean no cardinality.
        final int minimumOccurs, maximumOccurs;
        // Result of operation if applicable.
        final AbstractIdentifiedType resultType;
        if (propertyType instanceof AbstractOperation) {
            // May be null
            resultType = ((AbstractOperation) propertyType).getResult();
        } else {
            resultType = propertyType;
        }
        if (resultType instanceof DefaultAttributeType<?>) {
            final DefaultAttributeType<?> pt = (DefaultAttributeType<?>) resultType;
            minimumOccurs = pt.getMinimumOccurs();
            maximumOccurs = pt.getMaximumOccurs();
            valueClass = pt.getValueClass();
            valueType = getFormat(Class.class).format(valueClass, buffer, dummyFP).toString();
            buffer.setLength(0);
        } else if (resultType instanceof DefaultAssociationRole) {
            final DefaultAssociationRole pt = (DefaultAssociationRole) resultType;
            minimumOccurs = pt.getMinimumOccurs();
            maximumOccurs = pt.getMaximumOccurs();
            valueType = toString(DefaultAssociationRole.getValueTypeName(pt));
            valueClass = AbstractFeature.class;
        } else {
            valueType = (resultType != null) ? toString(resultType.getName()) : "";
            valueClass = null;
            minimumOccurs = -1;
            maximumOccurs = -1;
        }
        /*
             * At this point we determined that the row should not be skipped
             * and we got all information to format.
             */
        isFirstColumn = true;
        for (final Column column : visibleColumns) {
            if (!isFirstColumn)
                nextColumn(table);
            isFirstColumn = false;
            switch(column) {
                /*
                     * Human-readable name of the property. May contains any characters (spaces, ideographs, etc).
                     * In many cases, this information is not provided and the whole column is skipped.
                     */
                case DESIGNATION:
                    {
                        final InternationalString d = propertyType.getDesignation();
                        if (d != null)
                            table.append(d.toString(displayLocale));
                        break;
                    }
                /*
                     * Machine-readable name of the property (identifier). This information is mandatory.
                     * This name is usually shorter than the designation and should contain only valid
                     * Unicode identifier characters (e.g. no spaces).
                     */
                case NAME:
                    {
                        table.append(toString(propertyType.getName()));
                        break;
                    }
                /*
                     * The base class or interface for all values in properties of the same type.
                     * This is typically String, Number, Integer, Geometry or URL.
                     */
                case TYPE:
                    {
                        table.append(valueType);
                        break;
                    }
                /*
                     * Minimum and maximum number of occurrences allowed for this property.
                     * If we are formatting a Feature instead than a FeatureType, then the
                     * actual number of values is also formatted. Example: 42 ∈ [0 … ∞]
                     */
                case CARDINALITY:
                    {
                        table.setCellAlignment(TableAppender.ALIGN_RIGHT);
                        if (cardinality >= 0) {
                            table.append(getFormat(Integer.class).format(cardinality, buffer, dummyFP));
                            buffer.setLength(0);
                        }
                        if (maximumOccurs >= 0) {
                            if (cardinality >= 0) {
                                table.append(' ').append((cardinality >= minimumOccurs && cardinality <= maximumOccurs) ? '∈' : '∉').append(' ');
                            }
                            final Format format = getFormat(Integer.class);
                            table.append('[').append(format.format(minimumOccurs, buffer, dummyFP)).append(" … ");
                            buffer.setLength(0);
                            if (maximumOccurs != Integer.MAX_VALUE) {
                                table.append(format.format(maximumOccurs, buffer, dummyFP));
                            } else {
                                table.append('∞');
                            }
                            buffer.setLength(0);
                            table.append(']');
                        }
                        break;
                    }
                /*
                     * If formatting a FeatureType, the default value. If formatting a Feature, the actual value.
                     * A java.text.Format instance dedicated to the value class is used if possible. In addition
                     * to types for which a java.text.Format may be available, we also have to check for other
                     * special cases. If there is more than one value, they are formatted as a coma-separated list.
                     */
                case VALUE:
                    {
                        table.setCellAlignment(TableAppender.ALIGN_LEFT);
                        // Null if valueClass is null.
                        final Format format = getFormat(valueClass);
                        final Iterator<?> it = CollectionsExt.toCollection(value).iterator();
                        String separator = "";
                        int length = 0;
                        while (it.hasNext()) {
                            value = it.next();
                            if (value != null) {
                                if (propertyType instanceof DefaultAssociationRole) {
                                    final String p = DefaultAssociationRole.getTitleProperty((DefaultAssociationRole) propertyType);
                                    if (p != null) {
                                        value = ((AbstractFeature) value).getPropertyValue(p);
                                        if (value == null)
                                            continue;
                                    }
                                } else if (format != null && valueClass.isInstance(value)) {
                                    // Null safe because of getFormat(valueClass) contract.
                                    /*
                                     * Convert numbers, dates, angles, etc. to character sequences before to append them in the table.
                                     * Note that DecimalFormat writes Not-a-Number as "NaN" in some locales and as "�" in other locales
                                     * (U+FFFD - Unicode replacement character). The "�" seems to be used mostly for historical reasons;
                                     * as of 2017 the Unicode Common Locale Data Repository (CLDR) seems to define "NaN" for all locales.
                                     * We could configure DecimalFormatSymbols for using "NaN", but (for now) we rather substitute "�" by
                                     * "NaN" here for avoiding to change the DecimalFormat configuration and for distinguishing the NaNs.
                                     */
                                    final StringBuffer t = format.format(value, buffer, dummyFP);
                                    if (value instanceof Number) {
                                        final float f = ((Number) value).floatValue();
                                        if (Float.isNaN(f)) {
                                            if ("�".contentEquals(t)) {
                                                t.setLength(0);
                                                t.append("NaN");
                                            }
                                            try {
                                                final int n = MathFunctions.toNanOrdinal(f);
                                                if (n > 0)
                                                    t.append(" #").append(n);
                                            } catch (IllegalArgumentException e) {
                                                // May happen if the NaN is a signaling NaN instead than a quiet NaN.
                                                final int bits = Float.floatToRawIntBits(f);
                                                if (bits != illegalNaN) {
                                                    illegalNaN = bits;
                                                    Logging.recoverableException(Logging.getLogger(Modules.FEATURE), FeatureFormat.class, "format", e);
                                                }
                                            }
                                        }
                                    }
                                    value = t;
                                }
                                /*
                                 * All values: the numbers, dates, angles, etc. formatted above, any other character sequences
                                 * (e.g. InternationalString), or other kind of values - some of them handled in a special way.
                                 */
                                length = formatValue(value, table.append(separator), length);
                                buffer.setLength(0);
                                // Value is too long, abandon remaining iterations.
                                if (length < 0)
                                    break;
                                separator = SEPARATOR;
                                length += SEPARATOR.length();
                            }
                        }
                        break;
                    }
                /*
                     * Characteristics are optional information attached to some values. For example if a property
                     * value is a temperature measurement, a characteritic of that value may be the unit of measure.
                     * Characteristics are handled as "attributes of attributes".
                     */
                case CHARACTERISTICS:
                    {
                        if (propertyType instanceof DefaultAttributeType<?>) {
                            int length = 0;
                            String separator = "";
                            format: for (final DefaultAttributeType<?> ct : ((DefaultAttributeType<?>) propertyType).characteristics().values()) {
                                /*
                                 * Format the characteristic name. We will append the value(s) later.
                                 * We keep trace of the text length in order to stop formatting if the
                                 * text become too long.
                                 */
                                final GenericName cn = ct.getName();
                                final String cs = toString(cn);
                                table.append(separator).append(cs);
                                length += separator.length() + cs.length();
                                Collection<?> cv = CollectionsExt.singletonOrEmpty(ct.getDefaultValue());
                                if (feature != null) {
                                    /*
                                     * Usually, the property 'cp' below is null because all features use the same
                                     * characteristic value (for example the same unit of measurement),  which is
                                     * given by the default value 'cv'.  Nevertheless we have to check if current
                                     * feature overrides this characteristic.
                                     */
                                    final Object cp = feature.getProperty(propertyType.getName().toString());
                                    if (cp instanceof AbstractAttribute<?>) {
                                        // Should always be true, but we are paranoiac.
                                        AbstractAttribute<?> ca = ((AbstractAttribute<?>) cp).characteristics().get(cn.toString());
                                        if (ca != null)
                                            cv = ca.getValues();
                                    }
                                }
                                /*
                                 * Now format the value, separated from the name with " = ". Example: unit = m/s
                                 * If the value accepts multi-occurrences, we will format the value between {…}.
                                 * We use {…} because we may have more than one characteristic in the same cell,
                                 * so we need a way to distinguish multi-values from multi-characteristics.
                                 */
                                final boolean multi = ct.getMaximumOccurs() > 1;
                                String sep = multi ? " = {" : " = ";
                                for (Object c : cv) {
                                    length = formatValue(c, table.append(sep), length += sep.length());
                                    // Value is too long, abandon remaining iterations.
                                    if (length < 0)
                                        break format;
                                    sep = SEPARATOR;
                                }
                                separator = SEPARATOR;
                                if (multi && sep == SEPARATOR) {
                                    table.append('}');
                                }
                            }
                        }
                        break;
                    }
                case REMARKS:
                    {
                        if (org.apache.sis.feature.Field.isDeprecated(propertyType)) {
                            table.append(resources.getString(Vocabulary.Keys.Deprecated));
                            final InternationalString r = ((Deprecable) propertyType).getRemarks();
                            if (r != null) {
                                remarks.add(r.toString(displayLocale));
                                appendSuperscript(remarks.size(), table);
                            }
                        }
                        break;
                    }
            }
        }
        table.nextLine();
    }
    table.nextLine('─');
    table.flush();
    /*
         * If there is any remarks, write them below the table.
         */
    final int n = remarks.size();
    for (int i = 0; i < n; i++) {
        appendSuperscript(i + 1, toAppendTo);
        toAppendTo.append(' ').append(remarks.get(i)).append(lineSeparator);
    }
}
Also used : Vocabulary(org.apache.sis.util.resources.Vocabulary) TableAppender(org.apache.sis.io.TableAppender) ArrayList(java.util.ArrayList) UncheckedIOException(java.io.UncheckedIOException) InternationalString(org.opengis.util.InternationalString) GenericName(org.opengis.util.GenericName) Format(java.text.Format) TabularFormat(org.apache.sis.io.TabularFormat) Iterator(java.util.Iterator) Deprecable(org.apache.sis.util.Deprecable) IOException(java.io.IOException) UncheckedIOException(java.io.UncheckedIOException) FieldPosition(java.text.FieldPosition) InternationalString(org.opengis.util.InternationalString) Collection(java.util.Collection) IdentifiedObject(org.opengis.referencing.IdentifiedObject)

Aggregations

GenericName (org.opengis.util.GenericName)46 Test (org.junit.Test)11 ReferenceIdentifier (org.opengis.referencing.ReferenceIdentifier)9 InternationalString (org.opengis.util.InternationalString)9 ArrayList (java.util.ArrayList)5 IdentifiedObject (org.opengis.referencing.IdentifiedObject)5 NameFactory (org.opengis.util.NameFactory)5 Identifier (org.opengis.metadata.Identifier)4 ScopedName (org.opengis.util.ScopedName)4 HashMap (java.util.HashMap)3 DependsOnMethod (org.apache.sis.test.DependsOnMethod)3 IOException (java.io.IOException)2 UncheckedIOException (java.io.UncheckedIOException)2 Collection (java.util.Collection)2 IdentityHashMap (java.util.IdentityHashMap)2 LinkedHashMap (java.util.LinkedHashMap)2 Map (java.util.Map)2 AbstractIdentifiedType (org.apache.sis.feature.AbstractIdentifiedType)2 NameToIdentifier (org.apache.sis.internal.metadata.NameToIdentifier)2 TableAppender (org.apache.sis.io.TableAppender)2