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.


Reply via email to