You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2012/11/12 11:11:43 UTC
svn commit: r1408238 - in
/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util:
collection/ resources/
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.