]> source.dussan.org Git - vaadin-framework.git/commitdiff
Integrated patch that implements ItemSorter for IndexedContainer, #3434
authorMarc Englund <marc.englund@itmill.com>
Fri, 27 Nov 2009 08:38:54 +0000 (08:38 +0000)
committerMarc Englund <marc.englund@itmill.com>
Fri, 27 Nov 2009 08:38:54 +0000 (08:38 +0000)
svn changeset:10081/svn branch:6.2

src/com/vaadin/data/util/BeanItemContainer.java
src/com/vaadin/data/util/DefaultItemSorter.java [new file with mode: 0644]
src/com/vaadin/data/util/HierarchicalContainer.java
src/com/vaadin/data/util/IndexedContainer.java
src/com/vaadin/data/util/ItemSorter.java [new file with mode: 0644]

index aaa7d9cd560d6944d1b67128eeb7920fa285f724..2575615232a21fc39f184f34906fca2be5f408e1 100644 (file)
@@ -5,7 +5,6 @@ import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -52,6 +51,11 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
 
     private Set<Filter> filters = new HashSet<Filter>();
 
+    /**
+     * The item sorter which is used for sorting the container.
+     */
+    private ItemSorter itemSorter = new DefaultItemSorter();
+
     /* Special serialization to handle method references */
     private void readObject(java.io.ObjectInputStream in) throws IOException,
             ClassNotFoundException {
@@ -385,46 +389,33 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
         return sortables;
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.data.Container.Sortable#sort(java.lang.Object[],
+     * boolean[])
+     */
     public void sort(Object[] propertyId, boolean[] ascending) {
-        for (int i = 0; i < ascending.length; i++) {
-            final boolean asc = ascending[i];
-            final Object property = propertyId[i];
-            // sort allItems, then filter and notify
-            Collections.sort(allItems, new Comparator<BT>() {
-                @SuppressWarnings("unchecked")
-                public int compare(BT a, BT b) {
-                    Comparable va, vb;
-                    if (asc) {
-                        va = (Comparable) getItem(a).getItemProperty(property)
-                                .getValue();
-                        vb = (Comparable) getItem(b).getItemProperty(property)
-                                .getValue();
-                    } else {
-                        va = (Comparable) getItem(b).getItemProperty(property)
-                                .getValue();
-                        vb = (Comparable) getItem(a).getItemProperty(property)
-                                .getValue();
-                    }
-
-                    /*
-                     * Null values are considered less than all others. The
-                     * compareTo method cannot handle null values for the
-                     * standard types.
-                     */
-                    if (va == null) {
-                        return (vb == null) ? 0 : -1;
-                    } else if (vb == null) {
-                        return 1;
-                    }
-
-                    return va.compareTo(vb);
-                }
-            });
-        }
+        itemSorter.setSortProperties(this, propertyId, ascending);
+
+        doSort();
+
         // notifies if anything changes in the filtered list, including order
         filterAll();
     }
 
+    /**
+     * Perform the sorting of the data structures in the container. This is
+     * invoked when the <code>itemSorter</code> has been prepared for the sort
+     * operation. Typically this method calls
+     * <code>Collections.sort(aCollection, getItemSorter())</code> on all arrays
+     * (containing item ids) that need to be sorted.
+     * 
+     */
+    protected void doSort() {
+        Collections.sort(allItems, getItemSorter());
+    }
+
     public void addListener(ItemSetChangeListener listener) {
         if (itemSetChangeListeners == null) {
             itemSetChangeListeners = new LinkedList<ItemSetChangeListener>();
@@ -531,4 +522,12 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
         filterAll();
     }
 
+    public ItemSorter getItemSorter() {
+        return itemSorter;
+    }
+
+    public void setItemSorter(ItemSorter itemSorter) {
+        this.itemSorter = itemSorter;
+    }
+
 }
diff --git a/src/com/vaadin/data/util/DefaultItemSorter.java b/src/com/vaadin/data/util/DefaultItemSorter.java
new file mode 100644 (file)
index 0000000..4a99714
--- /dev/null
@@ -0,0 +1,197 @@
+package com.vaadin.data.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.List;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Item;
+import com.vaadin.data.Property;
+import com.vaadin.data.Container.Sortable;
+
+/**
+ * Provides a default implementation of an ItemSorter. The
+ * <code>DefaultItemSorter</code> adheres to the
+ * {@link Sortable#sort(Object[], boolean[])} rules and sorts the container
+ * according to the properties given using
+ * {@link #setSortProperties(Sortable, Object[], boolean[])}.
+ * <p>
+ * A Comparator is used for comparing the individual <code>Property</code>
+ * values. The comparator can be set using the constructor. If no comparator is
+ * provided a default comparator is used.
+ * 
+ */
+public class DefaultItemSorter implements ItemSorter {
+
+    private java.lang.Object[] sortPropertyIds;
+    private boolean[] sortDirections;
+    private Container container;
+    private Comparator<Object> propertyValueComparator;
+
+    /**
+     * Constructs a DefaultItemSorter using the default <code>Comparator</code>
+     * for comparing <code>Property</code>values.
+     * 
+     */
+    public DefaultItemSorter() {
+        this(new DefaultPropertyValueComparator());
+    }
+
+    /**
+     * Constructs a DefaultItemSorter which uses the <code>Comparator</code>
+     * indicated by the <code>propertyValueComparator</code> parameter for
+     * comparing <code>Property</code>values.
+     * 
+     * @param propertyValueComparator
+     *            The comparator to use when comparing individual
+     *            <code>Property</code> values
+     */
+    public DefaultItemSorter(Comparator<Object> propertyValueComparator) {
+        this.propertyValueComparator = propertyValueComparator;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.data.util.ItemSorter#compare(java.lang.Object,
+     * java.lang.Object)
+     */
+    public int compare(Object o1, Object o2) {
+        Item item1 = container.getItem(o1);
+        Item item2 = container.getItem(o2);
+
+        for (int i = 0; i < sortPropertyIds.length; i++) {
+
+            int result = compareProperty(sortPropertyIds[i], sortDirections[i],
+                    item1, item2);
+
+            // If order can be decided
+            if (result != 0) {
+                return result;
+            }
+
+        }
+
+        return 0;
+    }
+
+    /**
+     * Compares the property indicated by <code>propertyId</code> in the items
+     * indicated by <code>item1</code> and <code>item2</code> for order. Returns
+     * a negative integer, zero, or a positive integer as the property value in
+     * the first item is less than, equal to, or greater than the property value
+     * in the second item. If the <code>sortDirection</code> is false the
+     * returned value is negated.
+     * <p>
+     * The comparator set for this <code>DefaultItemSorter</code> is used for
+     * comparing the two property values.
+     * 
+     * @param propertyId
+     *            The property id for the property that is used for comparison.
+     * @param sortDirection
+     *            The direction of the sort. A false value negates the result.
+     * @param item1
+     *            The first item to compare.
+     * @param item2
+     *            The second item to compare.
+     * @return
+     */
+    protected int compareProperty(Object propertyId, boolean sortDirection,
+            Item item1, Item item2) {
+
+        // Get the properties to compare
+        final Property property1 = item1.getItemProperty(propertyId);
+        final Property property2 = item2.getItemProperty(propertyId);
+
+        // Get the values to compare
+        final Object value1 = (property1 == null) ? null : property1.getValue();
+        final Object value2 = (property2 == null) ? null : property2.getValue();
+
+        // Result of the comparison
+        int r = 0;
+        if (sortDirection) {
+            r = propertyValueComparator.compare(value1, value2);
+        } else {
+            r = propertyValueComparator.compare(value2, value1);
+        }
+
+        return r;
+    }
+
+    /*
+     * (non-Javadoc)
+     * 
+     * @see
+     * com.vaadin.data.util.ItemSorter#setSortProperties(com.vaadin.data.Container
+     * .Sortable, java.lang.Object[], boolean[])
+     */
+    public void setSortProperties(Container.Sortable container,
+            Object[] propertyId, boolean[] ascending) {
+        this.container = container;
+
+        // Removes any non-sortable property ids
+        final List<Object> ids = new ArrayList<Object>();
+        final List<Boolean> orders = new ArrayList<Boolean>();
+        final Collection sortable = container.getSortableContainerPropertyIds();
+        for (int i = 0; i < propertyId.length; i++) {
+            if (sortable.contains(propertyId[i])) {
+                ids.add(propertyId[i]);
+                orders.add(Boolean.valueOf(i < ascending.length ? ascending[i]
+                        : true));
+            }
+        }
+
+        sortPropertyIds = ids.toArray();
+        sortDirections = new boolean[orders.size()];
+        for (int i = 0; i < sortDirections.length; i++) {
+            sortDirections[i] = (orders.get(i)).booleanValue();
+        }
+
+    }
+
+    /**
+     * Provides a default comparator used for comparing {@link Property} values.
+     * The <code>DefaultPropertyValueComparator</code> assumes all objects it
+     * compares can be cast to Comparable.
+     * 
+     */
+    public static class DefaultPropertyValueComparator implements
+            Comparator<Object> {
+
+        public int compare(Object o1, Object o2) {
+            int r = 0;
+            // Normal non-null comparison
+            if (o1 != null && o2 != null) {
+                // FIXME: Use standard Boolean comparison as Boolean implements
+                // Comaprable since JDK1.5
+                if ((o1 instanceof Boolean) && (o2 instanceof Boolean)) {
+                    if (o1.equals(o2)) {
+                        r = 0; // both have the same boolean value
+                    } else if (((Boolean) o1).booleanValue()) {
+                        return 1; // true is greater than false
+                    } else {
+                        return -1;
+                    }
+                } else {
+                    // Assume the objects can be cast to Comparable, throw
+                    // ClassCastException otherwise.
+                    r = ((Comparable) o1).compareTo(o2);
+                }
+            } else if (o1 == o2) {
+                // Objects are equal if both are null
+                r = 0;
+            } else {
+                if (o1 == null) {
+                    r = -1; // null is less than non-null
+                } else {
+                    r = 1; // non-null is greater than null
+                }
+            }
+
+            return r;
+        }
+
+    }
+
+}
index a6af0427ad3793cc8cebb02ca1ced9aa41f37631..f5b65f1dad9fb0f2bd9ee8e6f5072db671d90c35 100644 (file)
@@ -308,12 +308,18 @@ public class HierarchicalContainer extends IndexedContainer implements
         return success;
     }
 
+    /*
+     * (non-Javadoc)
+     * 
+     * @see com.vaadin.data.util.IndexedContainer#doSort()
+     */
     @Override
-    void doSort() {
+    protected void doSort() {
         super.doSort();
-        Collections.sort(roots, this);
+
+        Collections.sort(roots, getItemSorter());
         for (LinkedList<Object> childList : children.values()) {
-            Collections.sort(childList, this);
+            Collections.sort(childList, getItemSorter());
         }
     }
 
index 15c36953a13b0cda7e2a48cc513cce1f86e1d235..609f4889386688659407b5a40020ee3673331ee0 100644 (file)
@@ -9,7 +9,6 @@ import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.EventObject;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -17,7 +16,6 @@ import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
-import java.util.List;
 import java.util.NoSuchElementException;
 
 import com.vaadin.data.Container;
@@ -49,8 +47,8 @@ import com.vaadin.data.Property;
 @SuppressWarnings("serial")
 public class IndexedContainer implements Container.Indexed,
         Container.ItemSetChangeNotifier, Container.PropertySetChangeNotifier,
-        Property.ValueChangeNotifier, Container.Sortable, Comparator<Object>,
-        Cloneable, Container.Filterable {
+        Property.ValueChangeNotifier, Container.Sortable, Cloneable,
+        Container.Filterable {
 
     /* Internal structure */
 
@@ -108,14 +106,9 @@ public class IndexedContainer implements Container.Indexed,
     private LinkedList itemSetChangeListeners = null;
 
     /**
-     * Temporary store for sorting property ids.
+     * The item sorter which is used for sorting the container.
      */
-    private Object[] sortPropertyId;
-
-    /**
-     * Temporary store for sorting direction.
-     */
-    private boolean[] sortDirection;
+    private ItemSorter itemSorter = new DefaultItemSorter();
 
     /**
      * Filters that are applied to the container to limit the items visible in
@@ -1379,49 +1372,31 @@ public class IndexedContainer implements Container.Indexed,
      * boolean[])
      */
     public void sort(Object[] propertyId, boolean[] ascending) {
+        // Set up the item sorter for the sort operation
+        itemSorter.setSortProperties(this, propertyId, ascending);
 
-        // Removes any non-sortable property ids
-        final List ids = new ArrayList();
-        final List<Boolean> orders = new ArrayList<Boolean>();
-        final Collection sortable = getSortableContainerPropertyIds();
-        for (int i = 0; i < propertyId.length; i++) {
-            if (sortable.contains(propertyId[i])) {
-                ids.add(propertyId[i]);
-                orders.add(Boolean.valueOf(i < ascending.length ? ascending[i]
-                        : true));
-            }
-        }
-
-        if (ids.size() == 0) {
-            return;
-        }
-        sortPropertyId = ids.toArray();
-        sortDirection = new boolean[orders.size()];
-        for (int i = 0; i < sortDirection.length; i++) {
-            sortDirection[i] = (orders.get(i)).booleanValue();
-        }
-
+        // Perform the actual sort
         doSort();
 
+        // Post sort updates
         if (filteredItemIds != null) {
             updateContainerFiltering();
         } else {
             fireContentsChange(-1);
         }
 
-        // Remove temporary references
-        sortPropertyId = null;
-        sortDirection = null;
-
     }
 
     /**
-     * Perform the sorting of the container. Called when everything needed for
-     * the compare function has been set up.
+     * Perform the sorting of the data structures in the container. This is
+     * invoked when the <code>itemSorter</code> has been prepared for the sort
+     * operation. Typically this method calls
+     * <code>Collections.sort(aCollection, getItemSorter())</code> on all arrays
+     * (containing item ids) that need to be sorted.
      * 
      */
-    void doSort() {
-        Collections.sort(itemIds, this);
+    protected void doSort() {
+        Collections.sort(itemIds, getItemSorter());
     }
 
     /*
@@ -1430,7 +1405,7 @@ public class IndexedContainer implements Container.Indexed,
      * @see com.vaadin.data.Container.Sortable#getSortableContainerPropertyIds
      * ()
      */
-    public Collection getSortableContainerPropertyIds() {
+    public Collection<?> getSortableContainerPropertyIds() {
 
         final LinkedList list = new LinkedList();
         for (final Iterator i = propertyIds.iterator(); i.hasNext();) {
@@ -1445,52 +1420,25 @@ public class IndexedContainer implements Container.Indexed,
     }
 
     /**
-     * Compares two items for sorting.
+     * Returns the ItemSorter used for comparing items in a sort. See
+     * {@link #setItemSorter(ItemSorter)} for more information.
      * 
-     * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
-     * @see #sort((java.lang.Object[], boolean[])
+     * @return The ItemSorter used for comparing two items in a sort.
      */
-    public int compare(Object o1, Object o2) {
-
-        for (int i = 0; i < sortPropertyId.length; i++) {
-
-            // Get the compared properties
-            final Property pp1 = getContainerProperty(o1, sortPropertyId[i]);
-            final Property pp2 = getContainerProperty(o2, sortPropertyId[i]);
-
-            // Get the compared values
-            final Object p1 = pp1 == null ? null : pp1.getValue();
-            final Object p2 = pp2 == null ? null : pp2.getValue();
-
-            // Result of the comparison
-            int r = 0;
-
-            // Normal non-null comparison
-            if (p1 != null && p2 != null) {
-                if ((p1 instanceof Boolean) && (p2 instanceof Boolean)) {
-                    r = p1.equals(p2) ? 0
-                            : ((sortDirection[i] ? 1 : -1) * (((Boolean) p1)
-                                    .booleanValue() ? 1 : -1));
-                } else {
-                    r = sortDirection[i] ? ((Comparable) p1).compareTo(p2)
-                            : -((Comparable) p1).compareTo(p2);
-                }
-            }
-
-            // If both are nulls
-            else if (p1 == p2) {
-                r = 0;
-            } else {
-                r = (sortDirection[i] ? 1 : -1) * (p1 == null ? -1 : 1);
-            }
-
-            // If order can be decided
-            if (r != 0) {
-                return r;
-            }
-        }
+    public ItemSorter getItemSorter() {
+        return itemSorter;
+    }
 
-        return 0;
+    /**
+     * Sets the ItemSorter used for comparing items in a sort. The ItemSorter is
+     * called for each collection that needs sorting. A default ItemSorter is
+     * used if this is not explicitly set.
+     * 
+     * @param itemSorter
+     *            The ItemSorter used for comparing two items in a sort.
+     */
+    public void setItemSorter(ItemSorter itemSorter) {
+        this.itemSorter = itemSorter;
     }
 
     /**
@@ -1524,10 +1472,7 @@ public class IndexedContainer implements Container.Indexed,
         nc.singlePropertyValueChangeListeners = singlePropertyValueChangeListeners != null ? (Hashtable) singlePropertyValueChangeListeners
                 .clone()
                 : null;
-        nc.sortDirection = sortDirection != null ? (boolean[]) sortDirection
-                .clone() : null;
-        nc.sortPropertyId = sortPropertyId != null ? (Object[]) sortPropertyId
-                .clone() : null;
+
         nc.types = types != null ? (Hashtable) types.clone() : null;
 
         nc.filters = filters == null ? null : (HashSet<Filter>) filters.clone();
diff --git a/src/com/vaadin/data/util/ItemSorter.java b/src/com/vaadin/data/util/ItemSorter.java
new file mode 100644 (file)
index 0000000..eb665b4
--- /dev/null
@@ -0,0 +1,52 @@
+package com.vaadin.data.util;
+
+import java.util.Comparator;
+
+import com.vaadin.data.Container;
+import com.vaadin.data.Container.Sortable;
+
+/**
+ * An item comparator which is compatible with the {@link Sortable} interface.
+ * The <code>ItemSorter</code> interface can be used in <code>Sortable</code>
+ * implementations to provide a custom sorting method. The interface
+ */
+public interface ItemSorter extends Comparator<Object>, Cloneable {
+
+    /**
+     * Sets the parameters for an upcoming sort operation. The parameters
+     * determine what container to sort and how the <code>ItemSorter</code>
+     * sorts the container.
+     * 
+     * @param container
+     *            The container that will be sorted. The container must contain
+     *            the propertyIds given in the <code>propertyId</code>
+     *            parameter.
+     * @param propertyId
+     *            The property ids used for sorting. The property ids must exist
+     *            in the container and should only be used if they are also
+     *            sortable, i.e include in the collection returned by
+     *            <code>container.getSortableContainerPropertyIds()</code>. See
+     *            {@link Sortable#sort(Object[], boolean[])} for more
+     *            information.
+     * @param ascending
+     *            Sorting order flags for each property id. See
+     *            {@link Sortable#sort(Object[], boolean[])} for more
+     *            information.
+     */
+    void setSortProperties(Container.Sortable container, Object[] propertyId,
+            boolean[] ascending);
+
+    /**
+     * Compares its two arguments for order. Returns a negative integer, zero,
+     * or a positive integer as the first argument is less than, equal to, or
+     * greater than the second.
+     * <p>
+     * The parameters for the <code>ItemSorter</code> <code>compare()</code>
+     * method must always be item ids which exist in the container set using
+     * {@link #setSortProperties(Sortable, Object[], boolean[])}.
+     * 
+     * @see Comparator#compare(Object, Object)
+     */
+    int compare(Object itemId1, Object itemId2);
+
+}