sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1408238 - in /sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util: collection/ resources/
Date Mon, 12 Nov 2012 10:11:43 GMT
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.



Mime
View raw message