Author: desruisseaux Date: Mon Nov 12 10:11:42 2012 New Revision: 1408238 URL: http://svn.apache.org/viewvc?rev=1408238&view=rev Log: Initial draft of a default TreeTable implementation.
Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java (with props) Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Collections.java sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTable.java sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Collections.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Collections.java?rev=1408238&r1=1408237&r2=1408238&view=diff ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Collections.java (original) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/Collections.java Mon Nov 12 10:11:42 2012 @@ -40,8 +40,9 @@ import static java.util.Collections.unmo * <ul> * <li>Null-safe {@link #isNullOrEmpty(Collection) isNullOrEmpty} method, * for the convenience of classes using the <cite>lazy instantiation</cite> pattern.</li> - * <li>{@link #asCollection(Object) asCollection} for wrapping arbitrary objects to list or collection.</li> - * <li>List and collection {@linkplain #listComparator() comparators}.</li> + * <li>{@link #toCollection(Object) toCollection} for wrapping or copying arbitrary objects to + * list or collection.</li> + * <li>List and sorted set {@linkplain #listComparator() comparators}.</li> * <li>{@link #modifiableCopy(Collection) modifiableCopy} method for taking a snapshot of an arbitrary * implementation into an unsynchronized, modifiable, in-memory object.</li> * <li>{@link #unmodifiableOrCopy(Set) unmodifiableOrCopy} methods, which may be slightly more @@ -157,6 +158,8 @@ public final class Collections extends S * converter, or {@code null} if {@code storage} was null. * * @see org.apache.sis.util.ObjectConverters#derivedSet(Set, ObjectConverter) + * + * @category converter */ public static <S,E> Set<E> derivedSet(final Set<S> storage, final ObjectConverter<S,E> converter) { ArgumentChecks.ensureNonNull("converter", converter); @@ -201,6 +204,8 @@ public final class Collections extends S * @see org.apache.sis.util.ObjectConverters#derivedMap(Map, ObjectConverter, ObjectConverter) * @see org.apache.sis.util.ObjectConverters#derivedKeys(Map, ObjectConverter, Class) * @see org.apache.sis.util.ObjectConverters#derivedValues(Map, Class, ObjectConverter) + * + * @category converter */ public static <SK,SV,K,V> Map<K,V> derivedMap(final Map<SK,SV> storage, final ObjectConverter<SK,K> keyConverter, @@ -225,6 +230,8 @@ public final class Collections extends S * @return A set containing the array elements, or {@code null} if the given array was null. * * @see java.util.Collections#unmodifiableSet(Set) + * + * @category converter */ @SafeVarargs public static <E> Set<E> immutableSet(final E... array) { @@ -253,6 +260,8 @@ public final class Collections extends S * @param <E> The type of elements in the set. * @param set The set to make unmodifiable, or {@code null}. * @return A unmodifiable version of the given set, or {@code null} if the given set was null. + * + * @category converter */ public static <E> Set<E> unmodifiableOrCopy(Set<E> set) { if (set != null) { @@ -289,6 +298,8 @@ public final class Collections extends S * @param <V> The type of values in the map. * @param map The map to make unmodifiable, or {@code null}. * @return A unmodifiable version of the given map, or {@code null} if the given map was null. + * + * @category converter */ public static <K,V> Map<K,V> unmodifiableOrCopy(Map<K,V> map) { if (map != null) { @@ -329,6 +340,8 @@ public final class Collections extends S * @param <E> The type of elements in the collection. * @param collection The collection to copy, or {@code null}. * @return A copy of the given collection, or {@code null} if the given collection was null. + * + * @category converter */ @SuppressWarnings("unchecked") public static <E> Collection<E> modifiableCopy(final Collection<E> collection) { @@ -380,6 +393,8 @@ public final class Collections extends S * @param <V> The type of values in the map. * @param map The map to copy, or {@code null}. * @return A copy of the given map, or {@code null} if the given map was null. + * + * @category converter */ @SuppressWarnings("unchecked") public static <K,V> Map<K,V> modifiableCopy(final Map<K,V> map) { @@ -418,16 +433,18 @@ public final class Collections extends S * is not valid anymore after this method call since it has been used for the iteration.</p> * * <p>If the returned object needs to be a list, then this method can be chained - * with {@link #asList(Collection)} as below:</p> + * with {@link #toList(Collection)} as below:</p> * * {@preformat java - * List<?> list = asList(asCollection(object)); + * List<?> list = toList(toCollection(object)); * } * * @param value The value to return as a collection, or {@code null}. * @return The value as a collection, or wrapped in a collection (never {@code null}). + * + * @category converter */ - public static Collection<?> asCollection(final Object value) { + public static Collection<?> toCollection(final Object value) { if (value == null) { return emptyList(); } @@ -467,18 +484,20 @@ public final class Collections extends S * <li>Otherwise the elements are copied in a new list, which is returned.</li> * </ul> * - * This method can be chained with {@link #asCollection(Object)} + * This method can be chained with {@link #toCollection(Object)} * for handling a wider range of types: * * {@preformat java - * List<?> list = asList(asCollection(object)); + * List<?> list = toList(toCollection(object)); * } * * @param <T> The type of elements in the given collection. * @param collection The collection to cast or copy to a list. * @return The given collection as a list, or a copy of the given collection. + * + * @category converter */ - public static <T> List<T> asList(final Collection<T> collection) { + public static <T> List<T> toList(final Collection<T> collection) { if (collection instanceof List<?>) { return (List<T>) collection; } @@ -486,38 +505,45 @@ public final class Collections extends S } /** - * The comparator to be returned by {@code #listComparator} and similar methods. Can not be - * public because of parameterized types: we need a method for casting to the expected type. - * This is the same trick than {@link Collections#emptySet()} for example. + * The comparator to be returned by {@link Collections#listComparator()} and similar methods. */ - @SuppressWarnings("rawtypes") - private static final class Compare implements Comparator<Collection<Comparable>>, Serializable { + private static final class Compare<T extends Comparable<T>> + implements Comparator<Collection<T>>, Serializable + { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = -8926770873102046405L; + /** - * The unique instance. + * The unique instance. Can not be public because of parameterized types: we need a method + * for casting to the expected type. This is the same trick than the one used by the JDK + * in the {@link Collections#emptySet()} method for instance. */ - static final Comparator<Collection<Comparable>> INSTANCE = new Compare(); + @SuppressWarnings("rawtypes") + static final Comparator INSTANCE = new Compare(); /** - * For cross-version compatibility. + * Do not allow instantiation other than the unique {@link #INSTANCE}. */ - private static final long serialVersionUID = -8926770873102046405L; + private Compare() { + } /** - * Compares to collections of comparable objects. + * Compares two collections of comparable objects. */ @Override - @SuppressWarnings("unchecked") - public int compare(final Collection<Comparable> c1, final Collection<Comparable> c2) { - final Iterator<Comparable> i1 = c1.iterator(); - final Iterator<Comparable> i2 = c2.iterator(); + public int compare(final Collection<T> c1, final Collection<T> c2) { + final Iterator<T> i1 = c1.iterator(); + final Iterator<T> i2 = c2.iterator(); int c; do { final boolean h1 = i1.hasNext(); final boolean h2 = i2.hasNext(); if (!h1) return h2 ? -1 : 0; if (!h2) return +1; - final Comparable e1 = i1.next(); - final Comparable e2 = i2.next(); + final T e1 = i1.next(); + final T e2 = i2.next(); c = e1.compareTo(e2); } while (c == 0); return c; @@ -525,8 +551,8 @@ public final class Collections extends S }; /** - * Returns a comparator for lists of comparable elements. The first element of each list - * are {@linkplain Comparable#compareTo compared}. If one is <cite>greater than</cite> or + * Returns a comparator for lists of comparable elements. The first element of each list are + * {@linkplain Comparable#compareTo(Object) compared}. If one is <cite>greater than</cite> or * <cite>less than</cite> the other, the result of that comparison is returned. Otherwise * the second element are compared, and so on until either non-equal elements are found, * or end-of-list are reached. In the later case, the shortest list is considered @@ -537,38 +563,91 @@ public final class Collections extends S * * @param <T> The type of elements in both lists. * @return The ordering between two lists. + * + * @category comparator */ - @SuppressWarnings({"unchecked","rawtypes"}) + @SuppressWarnings("unchecked") public static <T extends Comparable<T>> Comparator<List<T>> listComparator() { - return (Comparator) Compare.INSTANCE; + return Compare.INSTANCE; } /** - * Returns a comparator for sorted sets of comparable elements. The elements are compared in - * iteration order as for the {@linkplain #listComparator list comparator}. + * Returns a comparator for sorted sets of comparable elements. The first element of each set + * are {@linkplain Comparable#compareTo(Object) compared}. If one is <cite>greater than</cite> + * or <cite>less than</cite> the other, the result of that comparison is returned. Otherwise + * the second element are compared, and so on until either non-equal elements are found, + * or end-of-set are reached. In the later case, the smallest set is considered + * <cite>less than</cite> the largest one. + * + * {@note There is no method accepting an arbitrary <code>Set</code> or <code>Collection</code> + * argument because this comparator makes sense only for collections having determinist + * iteration order.} * * @param <T> The type of elements in both sets. * @return The ordering between two sets. + * + * @category comparator */ - @SuppressWarnings({"unchecked","rawtypes"}) + @SuppressWarnings("unchecked") public static <T extends Comparable<T>> Comparator<SortedSet<T>> sortedSetComparator() { - return (Comparator) Compare.INSTANCE; + return Compare.INSTANCE; } /** - * Returns a comparator for arbitrary collections of comparable elements. The elements are - * compared in iteration order as for the {@linkplain #listComparator list comparator}. + * The comparator to be returned by {@link Collections#valueComparator()}. + */ + private static final class ValueComparator<K,V extends Comparable<V>> + implements Comparator<Map.Entry<K,V>>, Serializable + { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = 3809610984070771228L; + + /** + * The unique instance. Can not be public because of parameterized types: we need a method + * for casting to the expected type. This is the same trick than the one used by the JDK + * in the {@link Collections#emptySet()} method for instance. + */ + @SuppressWarnings("rawtypes") + static final ValueComparator INSTANCE = new ValueComparator(); + + /** + * Do not allow instantiation other than the unique {@link #INSTANCE}. + */ + private ValueComparator() { + } + + /** + * Compares the values of two entries. + */ + @Override + public int compare(final Map.Entry<K,V> e1, final Map.Entry<K,V> e2) { + return e1.getValue().compareTo(e2.getValue()); + } + } + + /** + * Returns a comparator for map entries having comparable {@linkplain java.util.Map.Entry#getValue() values}. + * For any pair of entries {@code e1} and {@code e2}, this method performs the comparison as below: + * + * {@preformat java + * return e1.getValue().compareTo(e2.getValue()); + * } * - * <p><em>This comparator make sense only for collections having determinist order</em> - * like {@link java.util.TreeSet}, {@link java.util.LinkedHashSet} or queues. - * Do <strong>not</strong> use it with {@link java.util.HashSet}.</p> + * This comparator can be used as a complement to {@link SortedSet}. While {@code SortedSet} + * maintains keys ordering at all time, {@code valueComparator()} is typically used only at + * the end of a process in which the values are the numerical calculation results. + * + * @param <K> The type of keys in the map entries. + * @param <V> The type of values in the map entries. + * @return A comparator for the values of the given type. * - * @param <T> The type of elements in both collections. - * @return The ordering between two collections. + * @category comparator */ - @SuppressWarnings({"unchecked","rawtypes"}) - public static <T extends Comparable<T>> Comparator<Collection<T>> collectionComparator() { - return (Comparator) Compare.INSTANCE; + @SuppressWarnings("unchecked") + public static <K,V extends Comparable<V>> Comparator<Map.Entry<K,V>> valueComparator() { + return ValueComparator.INSTANCE; } /** Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java?rev=1408238&view=auto ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java (added) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java Mon Nov 12 10:11:42 2012 @@ -0,0 +1,414 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.sis.util.collection; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.io.Serializable; +import net.jcip.annotations.NotThreadSafe; +import org.apache.sis.util.ArgumentChecks; +import org.apache.sis.util.resources.Errors; + + +/** + * A {@link TreeTable} implementation with a {@linkplain #getColumns() list of columns} given at + * construction time. The list of columns is unmodifiable, but the {@linkplain #getRoot() root node} + * can be modified. + * + * <p>{@code DefaultTreeTable} accepts arbitrary {@link TreeTable.Node} implementations. + * However it is likely to be safer and more memory efficient when used together with the + * implementation provided in the {@link Node} inner class.</p> + * + * @author Martin Desruisseaux (Geomatys) + * @since 0.3 + * @version 0.3 + * @module + */ +@NotThreadSafe +public class DefaultTreeTable implements TreeTable, Serializable { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = 1951201018202846555L; + + /** + * The root node, or {@code null} if not yet specified. + * + * @see #getRoot() + * @see #setRoot(TreeTable.Node) + */ + private TreeTable.Node root; + + /** + * The table columns as an unmodifiable list, or {@code null} if not yet created. + * The content of this list is the {@link #columnIndex} keys sorted by their index values. + * + * @see #getColumns() + */ + private transient List<TableColumn<?>> columns; + + /** + * The index of values associated to each column. This is used by the {@link Node} + * implementation for storing values in a single flat array. After creation, this + * map shall be read-only since many {@code Node}Â instances may share it. + * + * {@note This field and the {@link #columns} field could be computed from each other. + * We serialize this field because children nodes will typically hold a reference + * to that map, and we want to preserve the references tree.} + * + * @see DefaultTreeTable.Node#columnIndex + */ + final Map<TableColumn<?>,Integer> columnIndex; + + /** + * Creates a new tree table with the given columns. The given array shall not be null or + * empty, and shall not contain null or duplicated elements. + * + * <p>The {@linkplain #getRoot() root} node is initially {@code null}. Callers can initialize + * it after construction time by a call to the {@link #setRoot(TreeTable.Node)} method.</p> + * + * @param columns The table columns. + */ + public DefaultTreeTable(TableColumn<?>... columns) { + ArgumentChecks.ensureNonNull("columns", columns); + if (columns.length == 0) { + throw new IllegalArgumentException(Errors.format(Errors.Keys.EmptyArgument_1, "columns")); + } + columns = columns.clone(); + this.columnIndex = createColumnIndex(columns); + this.columns = UnmodifiableArrayList.wrap(columns); + } + + /** + * Creates a new tree table initialized to the given root. + * The {@linkplain #getColumns() list of columns} is inferred from the given node. + * + * @param root The tree table root (can not be null). + */ + public DefaultTreeTable(final Node root) { + ArgumentChecks.ensureNonNull("root", root); + this.root = root; + columnIndex = root.columnIndex; + } + + /** + * Creates a map of column indices from the given list of columns. + * This method is invoked for initializing the {@link #columnIndex} field. + * + * @param columns The list of columns. + * @return The map of column indices. + */ + static Map<TableColumn<?>,Integer> createColumnIndex(final TableColumn<?>... columns) { + final Map<TableColumn<?>,Integer> map = new HashMap<>(Collections.hashMapCapacity(columns.length)); + for (int i=0; i<columns.length; i++) { + ArgumentChecks.ensureNonNull("columns", i, columns); + final TableColumn<?> column = columns[i]; + if (map.put(column, i) != null) { + throw new IllegalArgumentException(Errors.format(Errors.Keys.DuplicatedValue_1, column)); + } + } + return map; + } + + /** + * Returns all columns in the given map, sorted by increasing index value. + */ + static TableColumn<?>[] getColumns(final Map<TableColumn<?>,Integer> columnIndex) { + @SuppressWarnings({"unchecked","rawtypes"}) + final Map.Entry<TableColumn<?>,Integer>[] entries = + columnIndex.entrySet().toArray(new Map.Entry[columnIndex.size()]); + Arrays.sort(entries, Collections.<TableColumn<?>,Integer>valueComparator()); + final TableColumn<?>[] columns = new TableColumn<?>[entries.length]; + for (int i=0; i<columns.length; i++) { + columns[i] = entries[i].getKey(); + } + return columns; + } + + /** + * Returns the table columns given at construction time. + * The returned list is never null neither empty. + */ + @Override + public final List<TableColumn<?>> getColumns() { + if (columns == null) { + columns = UnmodifiableArrayList.wrap(getColumns(columnIndex)); + } + return columns; + } + + /** + * Returns the root node. This method returns the node specified at + * {@linkplain #DefaultTreeTable(Node) construction time} or to the + * last call of the {@link #setRoot(TreeTable.Node)} method. + * + * @throws IllegalStateException If the root node has not yet been specified. + */ + @Override + public TreeTable.Node getRoot() { + if (root == null) { + throw new IllegalStateException(Errors.format(Errors.Keys.NodeNotFound_1, "root")); + } + return root; + } + + /** + * Sets the root to the given node. If a root already existed prior this method call, + * then the previous root node will be discarded. + * + * @param root The new root node (can not be null). + * @throws IllegalArgumentException If the table columns in the given node are inconsistent + * with the table columns in this {@code DefaultTreeTable}. + */ + public void setRoot(final TreeTable.Node root) { + ArgumentChecks.ensureNonNull("root", root); + if (root instanceof Node) { + if (columnIndex.keySet().containsAll(((Node) root).columnIndex.keySet())) { + throw new IllegalArgumentException(Errors.format(Errors.Keys.InconsistentTableColumns)); + } + } + this.root = root; + } + + + + + /** + * A {@link TreeTable.Node} implementation which can store values for a pre-defined list + * of columns. + * + * <p>The {@linkplain #getChildren() list of children} provided by this class is <cite>live</cite>: + * adding a {@code Node} child to that list will automatically set its parent to {@code this}, + * and removing a {@code Node} from that list will set its parent to {@code null}.</p> + * + * @author Martin Desruisseaux (Geomatys) + * @since 0.3 + * @version 0.3 + * @module + */ + @NotThreadSafe + public static class Node implements TreeTable.Node, Serializable { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = 2931274954865719140L; + + /** + * Implementation of {@link Node} children list. This list updates automatically the + * {@link Node#parent} field when the enclosing node is added to or removed from the + * list of children of another {@code Node} instance. + */ + private static final class Children extends TreeNodeList { + /** + * For cross-version compatibility. + */ + private static final long serialVersionUID = -1543888535672160884L; + + /** + * Creates a new, initially empty, node list. The node given in argument to this + * constructor will be the parent of all nodes added as children to this list. + * + * @param parent The node which will own this list. + */ + Children(final TreeTable.Node parent) { + super(parent); + } + + /** + * Sets the parent of the given node if it is an instance of {@link Node}, + * or throws an exception otherwise. This method is invoked when a node is + * added to or removed from the list. + */ + @Override + protected void setParentOf(final TreeTable.Node node, final int mode) throws IllegalArgumentException { + if (!(node instanceof Node)) { + throw new IllegalArgumentException(Errors.format( + Errors.Keys.IllegalArgumentClass_3, "node", node.getClass(), Node.class)); + } + final TreeTable.Node p; + switch (mode) { + case NULL: p = null; break; + case THIS: p = parent; break; + case DRY_RUN: return; + default: throw new AssertionError(mode); + } + ((Node) node).setParent(p); + } + } + + /** + * The parent of this node, or {@code null} if none. + * + * @see #getParent() + * @see #setParent(TreeTable.Node) + */ + private TreeTable.Node parent; + + /** + * The list of children, or {@code null} if none. + * Created only when first needed. + */ + private List<TreeTable.Node> children; + + /** + * The index of values associated to each column. This map is used by the + * {@link #getValue(TableColumn)} and {@link #setValue(TableColumn, Object)} + * methods for identifying the index where to store values in the {@link #values} array. + * + * <p>This map shall be read-only since many {@code Node}Â instances may share it.</p> + * + * @see DefaultTreeTable#columnIndex + */ + final Map<TableColumn<?>,Integer> columnIndex; + + /** + * The values, or {@code null} if not yet created. + */ + private Object[] values; + + /** + * Creates a new node for the given table. The new node will be able to store a value + * for each {@linkplain TreeTable#getColumns() columns} defined in the given table. + * + * @param table The table for which this node is created. + */ + public Node(final TreeTable table) { + ArgumentChecks.ensureNonNull("table", table); + if (table instanceof DefaultTreeTable) { + // Share the same instance if possible. + columnIndex = ((DefaultTreeTable) table).columnIndex; + } else { + final List<TableColumn<?>> columns = table.getColumns(); + columnIndex = createColumnIndex(columns.toArray(new TableColumn<?>[columns.size()])); + } + } + + /** + * Creates a new node with the given parent. The new node will be able to store + * values for the same columns than the parent node. + * + * @param parent The parent of the new node. + */ + public Node(final Node parent) { + ArgumentChecks.ensureNonNull("parent", parent); + this.parent = parent; + columnIndex = parent.columnIndex; + } + + /** + * Returns the parent of this node. On {@code Node} creation, this value may be initially + * {@code null}. It will be automatically set to a non-null value when this node will be + * added as a child of another {@code Node} instance. + */ + @Override + public TreeTable.Node getParent() { + return parent; + } + + /** + * Sets the parent to the given node. Before doing so, this method ensures that the + * columns in this node are consistent with the columns in the parent node. + */ + final void setParent(final TreeTable.Node node) { + if (node instanceof Node) { + if (((Node) node).columnIndex.keySet().containsAll(columnIndex.keySet())) { + throw new IllegalArgumentException(Errors.format(Errors.Keys.InconsistentTableColumns)); + } + } + parent = node; + } + + /** + * Returns the node children. This list is modifiable and updates automatically the + * {@linkplain #getParent() parent} reference of any {@code Node} instance added to + * ore removed from this list. + */ + @Override + public List<TreeTable.Node> getChildren() { + if (children == null) { + children = new Children(this); + } + return children; + } + + /** + * Returns the value in the given column, or {@code null}Â if none. + * + * @param <T> The base type of values in the given column. + * @param column Identifier of the column from which to get the value. + * @return The value in the given column, or {@code null} if none. + */ + @Override + public <T> T getValue(final TableColumn<T> column) { + ArgumentChecks.ensureNonNull("column", column); + if (values != null) { + final Integer index = columnIndex.get(column); + if (index != null) { + return column.getElementType().cast(values[index]); + } + } + return null; + } + + /** + * Sets the value for the given column. + * The {@link #isEditable(TableColumn)} method can be invoked before this setter method + * for determining if the given column is modifiable. + * + * @param <T> The base type of values in the given column. + * @param column Identifier of the column into which to set the value. + * @param value The value to set. + * @throws IllegalArgumentException If the given column is not a legal column for this node. + * + * @see #isEditable(TableColumn) + */ + @Override + public <T> void setValue(final TableColumn<T> column, final T value) { + ArgumentChecks.ensureNonNull("column", column); + final Integer index = columnIndex.get(column); + if (index == null) { + throw new IllegalArgumentException(Errors.format( + Errors.Keys.IllegalArgumentValue_2, "column", column)); + } + if (values == null) { + if (value == null) return; + values = new Object[columnIndex.size()]; + } + values[index] = value; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isEditable(final TableColumn<?> column) { + ArgumentChecks.ensureNonNull("column", column); + return columnIndex.containsKey(column); + } + + /** + * Returns the user object associated to this node. + * The default implementation returns {@code null}. + */ + @Override + public Object getUserObject() { + return null; + } + } +} Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/DefaultTreeTable.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTable.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTable.java?rev=1408238&r1=1408237&r2=1408238&view=diff ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTable.java (original) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTable.java Mon Nov 12 10:11:42 2012 @@ -70,7 +70,7 @@ public interface TreeTable { * </ul></td> * <td><ul> * <li>{@link #getValue(TableColumn)}</li> - * <li>{@link #setValueAt(TableColumn, Object)}</li> + * <li>{@link #setValue(TableColumn, Object)}</li> * <li>{@link #isEditable(TableColumn)}</li> * </ul></td></tr> * </table> @@ -119,19 +119,24 @@ public interface TreeTable { * @param <T> The base type of values in the given column. * @param column Identifier of the column into which to set the value. * @param value The value to set. + * @throws IllegalArgumentException If the given column is not a legal column for this node. * @throws UnsupportedOperationException If values in the given column can not be modified. * * @see TreeTable#getColumns() * @see #isEditable(TableColumn) * @category table */ - <T> void setValueAt(TableColumn<T> column, T value) throws UnsupportedOperationException; + <T> void setValue(TableColumn<T> column, T value); /** - * Determines whether the specified column is editable. + * Determines whether the value in the specified column is editable. If the given + * column is not a legal column for this {@code Node} instance, then this method + * returns {@code false}. * * @param column The column to query. - * @return {@code true} if the column is editable, {@code false} otherwise. + * @return {@code true} if the given column is a legal column for this {@code Node} + * implementation and the corresponding value is editable, or {@code false} + * otherwise. * @category table */ boolean isEditable(TableColumn<?> column); Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1408238&r1=1408237&r2=1408238&view=diff ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java (original) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java Mon Nov 12 10:11:42 2012 @@ -46,6 +46,11 @@ public final class Errors extends Indexe } /** + * Value â{0}â is duplicated. + */ + public static final int DuplicatedValue_1 = 38; + + /** * Element â{0}â is already present. */ public static final int ElementAlreadyPresent_1 = 36; @@ -112,6 +117,11 @@ public final class Errors extends Indexe public static final int InconsistentAttribute_2 = 27; /** + * Inconsistent table columns. + */ + public static final int InconsistentTableColumns = 40; + + /** * Index {0} is out of bounds. */ public static final int IndexOutOfBounds_1 = 4; @@ -147,6 +157,11 @@ public final class Errors extends Indexe public static final int NodeHasNoParent_1 = 34; /** + * No â{0}â node found. + */ + public static final int NodeNotFound_1 = 39; + + /** * Argument â{0}â shall not be NaN (Not-a-Number). */ public static final int NotANumber_1 = 9; Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1408238&r1=1408237&r2=1408238&view=diff ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties (original) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties Mon Nov 12 10:11:42 2012 @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # +DuplicatedValue_1 = Value \u201c{0}\u201d is duplicated. ElementAlreadyPresent_1 = Element \u201c{0}\u201d is already present. EmptyArgument_1 = Argument \u2018{0}\u2019 shall not be empty. ForbiddenAttribute_2 = Attribute \u201c{0}\u201d is not allowed for an object of type \u2018{1}\u2019. @@ -27,6 +28,7 @@ IllegalFormatPatternForClass_2 = The \u IllegalLanguageCode_1 = The \u201c{0}\u201d language is not recognized. IllegalRange_2 = Range [{0} \u2026 {1}] is not valid. InconsistentAttribute_2 = Value \u201c{1}\u201d of attribute \u2018{0}\u2019 is inconsistent with other attributes. +InconsistentTableColumns = Inconsistent table columns. IndexOutOfBounds_1 = Index {0} is out of bounds. KeyCollision_1 = A different value is already associated to the \u201c{0}\u201d key. MandatoryAttribute_2 = Attribute \u201c{0}\u201d is mandatory for an object of type \u2018{1}\u2019. @@ -34,6 +36,7 @@ NegativeArgument_2 = Argume NodeChildOfItself_1 = Node \u201c{0}\u201d can not be a child of itself. NodeHasAnotherParent_1 = Node \u201c{0}\u201d already has another parent. NodeHasNoParent_1 = Node \u201c{0}\u201d has no parent. +NodeNotFound_1 = No \u201c{0}\u201d node found. NotANumber_1 = Argument \u2018{0}\u2019 shall not be NaN (Not-a-Number). NotAPrimitiveWrapper_1 = Class \u2018{0}\u2019 is not a primitive type wrapper. NullArgument_1 = Argument \u2018{0}\u2019 shall not be null. Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1408238&r1=1408237&r2=1408238&view=diff ============================================================================== --- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties (original) +++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties Mon Nov 12 10:11:42 2012 @@ -14,6 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # +DuplicatedValue_1 = La valeur \u201c{0}\u201d est dupliqu\u00e9e. ElementAlreadyPresent_1 = L\u2019\u00e9lement \u201c{0}\u201d est d\u00e9j\u00e0 pr\u00e9sent. EmptyArgument_1 = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre vide. ForbiddenAttribute_2 = L\u2019attribut \u201c{0}\u201d n\u2019est pas autoris\u00e9 pour un objet de type \u2018{1}\u2019. @@ -27,6 +28,7 @@ IllegalFormatPatternForClass_2 = Le mod IllegalLanguageCode_1 = Le code de langue \u201c{0}\u201d n\u2019est pas reconnu. IllegalRange_2 = La plage [{0} \u2026 {1}] n\u2019est pas valide. InconsistentAttribute_2 = La valeur \u201c{1}\u201d de l\u2019attribut \u2018{0}\u2019 n\u2019est pas coh\u00e9rente avec celles des autres attributs. +InconsistentTableColumns = Les colonnes des tables ne sont pas coh\u00e9rentes. IndexOutOfBounds_1 = L\u2019index {0} est en dehors des limites permises. KeyCollision_1 = Une valeur diff\u00e9rente est d\u00e9j\u00e0 associ\u00e9e \u00e0 la cl\u00e9 \u201c{0}\u201d. MandatoryAttribute_2 = L\u2019attribut \u201c{0}\u201d est obligatoire pour un objet de type \u2018{1}\u2019. @@ -34,6 +36,7 @@ NegativeArgument_2 = L\u201 NodeChildOfItself_1 = Le n\u0153ud \u201c{0}\u201d ne peut pas \u00eatre un enfant de lui-m\u00eame. NodeHasAnotherParent_1 = Le n\u0153ud \u201c{0}\u201d a d\u00e9j\u00e0 un autre parent. NodeHasNoParent_1 = Le n\u0153ud \u201c{0}\u201d n\u2019a pas de parent. +NodeNotFound_1 = Aucun n\u0153ud \u201c{0}\u201d n\u2019a \u00e9t\u00e9 trouv\u00e9. NotANumber_1 = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre NaN (Not-a-Number). NotAPrimitiveWrapper_1 = La classe \u2018{0}\u2019 n\u2019est pas un adaptateur d\u2019un type primitif. NullArgument_1 = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre nul.