/*
* Copyright 2009-2015 Jose Luis Martin
*
* Licensed 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.jdal.vaadin.data;
import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jdal.beans.PropertyUtils;
import org.springframework.beans.BeanUtils;
import com.vaadin.data.Container.Indexed;
import com.vaadin.data.Container.ItemSetChangeNotifier;
import com.vaadin.data.Container.PropertySetChangeNotifier;
import com.vaadin.data.Container.Sortable;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.AbstractContainer;
import com.vaadin.data.util.DefaultItemSorter;
import com.vaadin.data.util.ItemSorter;
/**
* Bean container that uses a Integer as itemId and {@link BeanWrapperItem} as Item.
* Hold data in a List.
*
* @author Jose Luis Martin
* @since 2.1
*/
public class ListBeanContainer extends AbstractContainer implements Indexed, Sortable,
ItemSetChangeNotifier, PropertySetChangeNotifier {
/** Hold all beans in container */
private transient List<Item> items = new ArrayList<Item>();
/** Bean type */
private Class<?> beanClass;
/** Bean properties used by container */
private List<String> properties = new ArrayList<String>();
private Map<String, PropertyDescriptor> propertyDescriptors =
new HashMap<String, PropertyDescriptor>();
public ListBeanContainer(Class<?> beanClass) {
this(beanClass, null, null);
}
public ListBeanContainer(Class<?> beanClass, Collection<?> data) {
this(beanClass, data, null);
}
public ListBeanContainer(Class<?> beanClass, Collection<?> data, List<String> properties) {
this.beanClass = beanClass;
if (properties == null) {
initDefaultProperties();
}
else {
setProperties(properties);
}
if (data != null)
init(data);
}
private void setProperties(List<String> properties) {
this.properties.clear();
this.propertyDescriptors.clear();
for (String propertyName : properties) {
addProperty(propertyName);
}
fireContainerPropertySetChange();
}
private void initDefaultProperties() {
for (PropertyDescriptor pd : BeanUtils.getPropertyDescriptors(beanClass)) {
this.properties.add(pd.getName());
this.propertyDescriptors.put(pd.getName(), pd);
}
}
private void init(Collection<?> data) {
for (Object bean : data) {
this.items.add(createItem(bean));
}
fireItemSetChange();
}
@Override
public Integer nextItemId(Object itemId) {
Integer index = getAsIndex(itemId);
return items.size() > index - 1 ? index + 1 : null;
}
/**
* Gets an itemId as Long
* @param itemId itemId to check
* @return long value
*/
private Integer getAsIndex(Object itemId) {
if (itemId instanceof Integer)
return (Integer) itemId;
else if (itemId instanceof Long)
return ((Long) itemId).intValue();
String clazzName = itemId != null ? itemId.getClass().getName() : "null";
throw new IllegalArgumentException("Expected Integer, found + [" + clazzName + "]");
}
@Override
public Integer prevItemId(Object itemId) {
Integer index = getAsIndex(itemId);
return index > 1 ? index - 1 : null;
}
@Override
public Integer firstItemId() {
return items.isEmpty() ? null : 0;
}
@Override
public Integer lastItemId() {
return items.isEmpty() ? null : items.size() - 1;
}
@Override
public boolean isFirstId(Object itemId) {
return getAsIndex(itemId) == 0;
}
@Override
public boolean isLastId(Object itemId) {
return getAsIndex(itemId) == items.size() - 1;
}
@Override
public Object addItemAfter(Object previousItemId)
throws UnsupportedOperationException {
return null;
}
@Override
public Item addItemAfter(Object previousItemId, Object newItemId)
throws UnsupportedOperationException {
return null;
}
@Override
public Item getItem(Object itemId) {
return items.get(getAsIndex(itemId));
}
@Override
public Collection<?> getContainerPropertyIds() {
return this.properties;
}
@Override
public Collection<?> getItemIds() {
List<Integer> itemIds = new ArrayList<Integer>();
for (int i = 0; i < this.items.size(); i++)
itemIds.add(new Integer(i));
return itemIds;
}
@Override
@SuppressWarnings("rawtypes")
public Property getContainerProperty(Object itemId, Object propertyId) {
int index = getAsIndex(itemId);
if (index > this.items.size() - 1)
return null;
return this.items.get(index).getItemProperty(propertyId);
}
@Override
public Class<?> getType(Object propertyId) {
return getPropertyDescriptor(propertyId).getPropertyType();
}
private PropertyDescriptor getPropertyDescriptor(Object propertyId) {
return propertyDescriptors.get(propertyId);
}
@Override
public int size() {
return this.items.size();
}
@Override
public boolean containsId(Object itemId) {
if (this.items.isEmpty())
return false;
int index = getAsIndex(itemId);
return index >= 0 && index < this.items.size();
}
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
Item item = createItem(itemId);
if (this.items.add(item)) {
fireItemSetChange();
return item;
}
return null;
}
@Override
public Object addItem() throws UnsupportedOperationException {
if (this.items.add(createItem(newBean()))) {
fireItemSetChange();
return this.items.size() - 1;
}
return null;
}
/**
* Create item from bean.
* @param bean bean for item
* @return new item.
*/
protected Item createItem(Object bean) {
return new BeanWrapperItem(bean, this.properties);
}
private Object newBean() {
return BeanUtils.instantiate(this.beanClass);
}
@Override
public boolean removeItem(Object itemId)
throws UnsupportedOperationException {
boolean result = this.items.remove(getAsIndex(itemId));
fireItemSetChange();
return result;
}
@Override
public boolean addContainerProperty(Object propertyId, Class<?> type,
Object defaultValue) throws UnsupportedOperationException {
if (!this.properties.contains((String) propertyId)) {
addProperty((String) propertyId);
return true;
}
return false;
}
@Override
public boolean removeContainerProperty(Object propertyId)
throws UnsupportedOperationException {
this.properties.remove(propertyId);
this.propertyDescriptors.remove(propertyId);
return true;
}
@Override
public boolean removeAllItems() throws UnsupportedOperationException {
this.items.clear();
fireItemSetChange();
return true;
}
@Override
public int indexOfId(Object itemId) {
return getAsIndex(itemId);
}
@Override
public Object getIdByIndex(int index) {
return index;
}
@Override
public List<?> getItemIds(int startIndex, int numberOfItems) {
List<Integer> indexes = new ArrayList<Integer>();
for (int i = startIndex; i < startIndex + numberOfItems; i++)
indexes.add(i);
return indexes;
}
@Override
public Object addItemAt(int index) throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
@Override
public Item addItemAt(int index, Object newItemId)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
public void addAll(Collection<?> data) {
init(data);
}
public void addProperty(String name) {
this.properties.add(name);
this.propertyDescriptors.put(name,
PropertyUtils.getPropertyDescriptor(this.beanClass, name));
}
@Override
public void addPropertySetChangeListener(
PropertySetChangeListener listener) {
super.addPropertySetChangeListener(listener);
}
@Override
public void addItemSetChangeListener(ItemSetChangeListener listener) {
super.addItemSetChangeListener(listener);
}
@Override
public void addListener(PropertySetChangeListener listener) {
super.addListener(listener);
}
@Override
public void addListener(ItemSetChangeListener listener) {
super.addListener(listener);
}
@Override
public void removePropertySetChangeListener(
PropertySetChangeListener listener) {
super.removePropertySetChangeListener(listener);
}
@Override
public void removeListener(PropertySetChangeListener listener) {
super.removeListener(listener);
}
@Override
public void removeItemSetChangeListener(ItemSetChangeListener listener) {
super.removeItemSetChangeListener(listener);
}
@Override
public void removeListener(ItemSetChangeListener listener) {
super.removeListener(listener);
}
@Override
public void sort(Object[] propertyId, boolean[] ascending) {
ItemSorter itemSorter = new DefaultItemSorter();
itemSorter.setSortProperties((Sortable) this, propertyId,ascending);
Collections.sort(this.items, itemSorter);
}
@Override
public Collection<?> getSortableContainerPropertyIds() {
return this.properties;
}
}