summaryrefslogtreecommitdiffstats
path: root/src/com/vaadin/data/util/BeanItemContainer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/vaadin/data/util/BeanItemContainer.java')
-rw-r--r--src/com/vaadin/data/util/BeanItemContainer.java127
1 files changed, 92 insertions, 35 deletions
diff --git a/src/com/vaadin/data/util/BeanItemContainer.java b/src/com/vaadin/data/util/BeanItemContainer.java
index 7848de5eed..6510229d5a 100644
--- a/src/com/vaadin/data/util/BeanItemContainer.java
+++ b/src/com/vaadin/data/util/BeanItemContainer.java
@@ -38,9 +38,23 @@ import com.vaadin.data.Property.ValueChangeNotifier;
@SuppressWarnings("serial")
public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
ItemSetChangeNotifier, ValueChangeListener {
- // filtered and unfiltered item IDs
- private ArrayList<BT> list = new ArrayList<BT>();
- private ArrayList<BT> allItems = new ArrayList<BT>();
+ /**
+ * The filteredItems variable contains the items that are visible outside
+ * the container. If filters are enabled this contains a subset of allItems,
+ * if no filters are set this contains the same items as allItems.
+ */
+ private ListSet<BT> filteredItems = new ListSet<BT>();
+
+ /**
+ * The allItems variable always contains all the items in the container.
+ * Some or all of these are also in the filteredItems list.
+ */
+ private ListSet<BT> allItems = new ListSet<BT>();
+
+ /**
+ * Maps all pojos (item ids) in the container (including filtered) to their
+ * corresponding BeanItem.
+ */
private final Map<BT, BeanItem<BT>> beanToItem = new HashMap<BT, BeanItem<BT>>();
// internal data model to obtain property IDs etc.
@@ -89,6 +103,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
* @throws IllegalArgumentException
* If the collection is null or empty.
*/
+ @SuppressWarnings("unchecked")
public BeanItemContainer(Collection<BT> collection)
throws IllegalArgumentException {
if (collection == null || collection.isEmpty()) {
@@ -98,10 +113,22 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
type = (Class<? extends BT>) collection.iterator().next().getClass();
model = BeanItem.getPropertyDescriptors(type);
- int i = 0;
- for (BT bt : collection) {
- addItemAt(i++, bt);
+ addAll(collection);
+ }
+
+ private void addAll(Collection<BT> collection) {
+ // Pre-allocate space for the collection
+ allItems.ensureCapacity(allItems.size() + collection.size());
+
+ int idx = size();
+ for (BT bean : collection) {
+ if (internalAddAt(idx, bean) != null) {
+ idx++;
+ }
}
+
+ // Filter the contents when all items have been added
+ filterAll();
}
/**
@@ -147,36 +174,65 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
* @return Returns new item or null if the operation fails.
*/
private BeanItem<BT> addItemAtInternalIndex(int index, Object newItemId) {
- // Make sure that the Item has not been created yet
- if (allItems.contains(newItemId)) {
+ BeanItem<BT> beanItem = internalAddAt(index, (BT) newItemId);
+ if (beanItem != null) {
+ filterAll();
+ }
+
+ return beanItem;
+ }
+
+ /**
+ * Adds the bean to all internal data structures at the given position.
+ * Fails if the bean is already in the container or is not assignable to the
+ * correct type. Returns the new BeanItem if the bean was added
+ * successfully.
+ *
+ * <p>
+ * Caller should call {@link #filterAll()} after calling this method to
+ * ensure the filtered list is updated.
+ * </p>
+ *
+ * @param position
+ * The position at which the bean should be inserted
+ * @param bean
+ * The bean to insert
+ *
+ * @return true if the bean was added successfully, false otherwise
+ */
+ private BeanItem<BT> internalAddAt(int position, BT bean) {
+ // Make sure that the item has not been added previously
+ if (allItems.contains(bean)) {
return null;
}
- if (type.isAssignableFrom(newItemId.getClass())) {
- BT pojo = (BT) newItemId;
- // "list" will be updated in filterAll()
- allItems.add(index, pojo);
- BeanItem<BT> beanItem = new BeanItem<BT>(pojo, model);
- beanToItem.put(pojo, beanItem);
- // add listeners to be able to update filtering on property changes
- for (Filter filter : filters) {
- // addValueChangeListener avoids adding duplicates
- addValueChangeListener(beanItem, filter.propertyId);
- }
- // it is somewhat suboptimal to filter all items
- filterAll();
- return beanItem;
- } else {
+ if (!type.isAssignableFrom(bean.getClass())) {
return null;
}
+
+ // "filteredList" will be updated in filterAll() which should be invoked
+ // by the caller after calling this method.
+ allItems.add(position, bean);
+ BeanItem<BT> beanItem = new BeanItem<BT>(bean, model);
+ beanToItem.put(bean, beanItem);
+
+ // add listeners to be able to update filtering on property
+ // changes
+ for (Filter filter : filters) {
+ // addValueChangeListener avoids adding duplicates
+ addValueChangeListener(beanItem, filter.propertyId);
+ }
+
+ return beanItem;
}
+ @SuppressWarnings("unchecked")
public BT getIdByIndex(int index) {
- return list.get(index);
+ return filteredItems.get(index);
}
public int indexOfId(Object itemId) {
- return list.indexOf(itemId);
+ return filteredItems.indexOf(itemId);
}
/**
@@ -296,7 +352,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
public boolean containsId(Object itemId) {
// only look at visible items after filtering
- return list.contains(itemId);
+ return filteredItems.contains(itemId);
}
public Property getContainerProperty(Object itemId, Object propertyId) {
@@ -311,8 +367,9 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
return beanToItem.get(itemId);
}
+ @SuppressWarnings("unchecked")
public Collection<BT> getItemIds() {
- return (Collection<BT>) list.clone();
+ return (Collection<BT>) filteredItems.clone();
}
public Class<?> getType(Object propertyId) {
@@ -321,7 +378,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
public boolean removeAllItems() throws UnsupportedOperationException {
allItems.clear();
- list.clear();
+ filteredItems.clear();
// detach listeners from all BeanItems
for (BeanItem<BT> item : beanToItem.values()) {
removeAllValueChangeListeners(item);
@@ -345,7 +402,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
removeAllValueChangeListeners(getItem(itemId));
// remove item
beanToItem.remove(itemId);
- list.remove(itemId);
+ filteredItems.remove(itemId);
fireItemSetChange();
return true;
}
@@ -375,7 +432,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
}
public int size() {
- return list.size();
+ return filteredItems.size();
}
public Collection<Object> getSortableContainerPropertyIds() {
@@ -445,7 +502,7 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
public void addContainerFilter(Object propertyId, String filterString,
boolean ignoreCase, boolean onlyMatchPrefix) {
if (filters.isEmpty()) {
- list = (ArrayList<BT>) allItems.clone();
+ filteredItems = (ListSet<BT>) allItems.clone();
}
// listen to change events to be able to update filtering
for (BeanItem<BT> item : beanToItem.values()) {
@@ -465,22 +522,22 @@ public class BeanItemContainer<BT> implements Indexed, Sortable, Filterable,
*/
protected void filterAll() {
// avoid notification if the filtering had no effect
- List<BT> originalItems = list;
+ List<BT> originalItems = filteredItems;
// it is somewhat inefficient to do a (shallow) clone() every time
- list = (ArrayList<BT>) allItems.clone();
+ filteredItems = (ListSet<BT>) allItems.clone();
for (Filter f : filters) {
filter(f);
}
// check if exactly the same items are there after filtering to avoid
// unnecessary notifications
// this may be slow in some cases as it uses BT.equals()
- if (!originalItems.equals(list)) {
+ if (!originalItems.equals(filteredItems)) {
fireItemSetChange();
}
}
protected void filter(Filter f) {
- Iterator<BT> iterator = list.iterator();
+ Iterator<BT> iterator = filteredItems.iterator();
while (iterator.hasNext()) {
BT bean = iterator.next();
if (!f.passesFilter(getItem(bean))) {