package enterpriseapp.ui.crud; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import com.vaadin.data.Container; import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.Validator; import com.vaadin.data.Validator.InvalidValueException; import com.vaadin.data.util.BeanContainer; import com.vaadin.ui.Button; import com.vaadin.ui.Component; import com.vaadin.ui.Field; import com.vaadin.ui.Table; import com.vaadin.ui.TableFieldFactory; import com.vaadin.ui.themes.Reindeer; import enterpriseapp.Utils; import enterpriseapp.hibernate.CustomHbnContainer.EntityItem; import enterpriseapp.hibernate.DefaultHbnContainer; import enterpriseapp.hibernate.annotation.CrudField; import enterpriseapp.hibernate.annotation.Downloadable; import enterpriseapp.hibernate.dto.Dto; import enterpriseapp.ui.Constants; /** * A CRUD Table used by CrudComponent. * * @author Alejandro Duarte * * @param <T> CRUD Entity type. */ public class CrudTable<T extends Dto> extends Table implements FieldContainer { private static final long serialVersionUID = 1L; protected Class<T> type; protected Container container; protected Button newButton = new Button(Constants.uiAdd); protected Button deleteButton = new Button(Constants.uiDelete); protected HashMap<Item, HashMap<Object, Field>> fields; protected PropertyFormatter propertyFormatter; /** * @param type Entity type. * @param container Container to use. * @param fieldFactory TableFieldFactory to use in editable mode. */ public CrudTable(Class<T> type, Container container, final TableFieldFactory fieldFactory) { this.type = type; this.container = container; propertyFormatter = new DefaultPropertyFormatter(); setTableFieldFactory(new TableFieldFactory() { private static final long serialVersionUID = 1L; @Override public Field createField(Container container, Object itemId, Object propertyId, Component uiContext) { Field field = getField(propertyId, getItem(itemId)); if(field == null) { field = fieldFactory.createField(container, itemId, propertyId, uiContext); } return field; } }); setBuffered(false); setMultiSelect(true); setContainerDataSource(container); configureColumns(); updateTable(); initLayout(); } /** * Inits the component layout. */ public void initLayout() { newButton.setStyleName(Reindeer.BUTTON_SMALL); deleteButton.setStyleName(Reindeer.BUTTON_SMALL); setSizeFull(); setSelectable(true); setImmediate(true); setColumnCollapsingAllowed(true); setColumnReorderingAllowed(true); } /** * Configures visible columns. */ public void configureColumns() { Object[] allColumns = getVisibleColumns(); ArrayList<Object> collapsedColumns = new ArrayList<Object>(); for(Object column : allColumns) { if(isColumnCollapsed(column)) { collapsedColumns.add(column); } } setVisibleColumns(allColumns); for(Object column : collapsedColumns) { setColumnCollapsed(column, true); } } /** * Updates table's content. */ @SuppressWarnings("unchecked") public void updateTable() { if(DefaultHbnContainer.class.isAssignableFrom(container.getClass())) { ((DefaultHbnContainer<T>) container).refresh(); } } public boolean isVisibleColumn(Object column) { try { java.lang.reflect.Field declaredField = type.getDeclaredField((String) column); CrudField crudAnnotation = declaredField.getAnnotation(CrudField.class); Downloadable downloadableAnnotation = declaredField.getAnnotation(Downloadable.class); boolean expresslyShowColumn = crudAnnotation != null && crudAnnotation.showInTable(); boolean expresslyHideColumn = crudAnnotation != null && !crudAnnotation.showInTable(); boolean automaticallyHideColum = downloadableAnnotation != null; return !expresslyHideColumn && (expresslyShowColumn || !automaticallyHideColum); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); newButton.setVisible(enabled); deleteButton.setVisible(enabled); } @Override public void setEditable(boolean editable) { super.setEditable(editable); newButton.setVisible(editable); deleteButton.setVisible(editable); } @Override public String getColumnHeader(Object propertyId) { String typeName = type.getSimpleName(); String nameFromFile = Utils.getPropertyLabel(typeName, propertyId); return nameFromFile.isEmpty() ? super.getColumnHeader(propertyId) : nameFromFile; } @SuppressWarnings("rawtypes") @Override public String formatPropertyValue(Object rowId, Object colId, Property property) { String value = null; if(property != null) { try { Object bean = null; if(container instanceof BeanContainer) { bean = ((BeanContainer) container).getItem(rowId).getBean(); } else { bean = ((EntityItem.EntityProperty) property).getPojo(); } String propertyName = colId.toString(); Class<?> clazz = type.getDeclaredField(propertyName).getType(); String capitalizedPropertyName = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1, propertyName.length()); String propertyGetterName; if(clazz == boolean.class || clazz == Boolean.class) { propertyGetterName = "is" + capitalizedPropertyName; } else { propertyGetterName = "get" + capitalizedPropertyName; } CrudField crudFieldAnnotation = type.getDeclaredField(propertyName).getAnnotation(CrudField.class); Method propertyGetter = type.getMethod(propertyGetterName, (Class<?>[]) null); Object propertyObject = propertyGetter.invoke(bean, (Object[]) null); if(propertyObject == null) { return ""; } Class<?> returnType = propertyGetter.getReturnType(); value = propertyFormatter.formatPropertyValue(rowId, colId, property, bean, propertyObject, returnType, crudFieldAnnotation, this); } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchMethodException e) { throw new RuntimeException(e); } catch (IllegalArgumentException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e); } } if(value == null) { value = super.formatPropertyValue(rowId, colId, property); } return value; } @Override public void addField(Field field, Object propertyId, Item item) { if(fields == null) { fields = new HashMap<Item, HashMap<Object, Field>>(); } HashMap<Object, Field> rowMap = fields.get(item); if(rowMap == null) { rowMap = new HashMap<Object, Field>(); fields.put(item, rowMap); } rowMap.remove(propertyId); rowMap.put(propertyId, field); } @Override public Field getField(Object propertyId, Item item) { Field field = null; if(fields != null) { HashMap<Object, Field> rowMap = fields.get(item); if(rowMap != null) { field = rowMap.get(propertyId); } } return field; } /** * @return The table fields when editable mode is on. */ public Collection<Field> getFields() { ArrayList<Field> list = new ArrayList<Field>(); if(fields != null) { for(HashMap<Object, Field> map : fields.values()) { list.addAll(map.values()); } } return list; } /** * Removes the fields for the specified item when editable mode is on. * @param item */ public void removeFields(Item item) { if(fields != null) { fields.remove(item); } } /** * Removes all fields when editable mode is on. */ public void removeAllFields() { if(fields != null) { fields.clear(); } } @Override public boolean isValid() { try { validate(); } catch (InvalidValueException e) { return false; } return true; } @Override public void validate() throws Validator.InvalidValueException { super.validate(); if(fields != null) { for(HashMap<Object, Field> map : fields.values()) { for(Field field : map.values()) { field.validate(); } } } } /** * @return CRUD Entity type. */ public Class<T> getType() { return type; } /** * Sets a custom PropertyFormatter * @param propertyFormatter PropertyFormatter to use. */ public void setPropertyFormatter(PropertyFormatter propertyFormatter) { this.propertyFormatter = propertyFormatter; } }