package au.com.vaadinutils.crud; import java.util.Map; import java.util.Set; import java.util.UUID; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.vaadin.addon.jpacontainer.EntityItem; import com.vaadin.addon.jpacontainer.JPAContainer; import com.vaadin.data.Property; import com.vaadin.data.util.converter.Converter; import com.vaadin.event.ItemClickEvent; import com.vaadin.event.ItemClickEvent.ItemClickListener; import com.vaadin.shared.MouseEventDetails.MouseButton; import com.vaadin.ui.Table; import com.vaadin.ui.themes.ValoTheme; import au.com.vaadinutils.errorHandling.ErrorWindow; public class EntityTable<E> extends Table implements EntityList<E> { private static final long serialVersionUID = 1L; private JPAContainer<E> entityContainer; private RowChangeListener<E> rowChangeListener; private HeadingPropertySet columnConfiguration; transient Logger logger = LogManager.getLogger(EntityTable.class); public EntityTable(JPAContainer<E> entityContainer, HeadingPropertySet headingPropertySet) { this.entityContainer = entityContainer; this.columnConfiguration = headingPropertySet; addStyleName(ValoTheme.TABLE_COMPACT); this.setContainerDataSource(entityContainer); addRightClickSelect(); } @Override public Object prevVisibleItemId(Object itemId) { Object prev = null; for (Object id : getVisibleItemIds()) { if (id.equals(itemId)) { return prev; } prev = id; } return prev; } @Override public void setRowChangeListener(RowChangeListener<E> rowChangeListener) { this.rowChangeListener = rowChangeListener; } /** * @param uniqueTableId * -an id for this layout/table combination, it is used to * identify stored column settings in a key value map */ @Override public void init(String uniqueTableId) { columnConfiguration.applyToTable(this, uniqueTableId); this.setSelectable(true); this.setImmediate(true); this.setColumnReorderingAllowed(true); this.addValueChangeListener(new Property.ValueChangeListener() { private static final long serialVersionUID = 1L; @Override public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) { try { if (EntityTable.this.rowChangeListener != null) { Object entityId = EntityTable.this.getValue(); if (entityId != null) // it can be null when a row is // being // deleted. { EntityItem<E> entity = EntityTable.this.entityContainer.getItem(entityId); // .getEntity(); EntityTable.this.rowChangeListener.rowChanged(entity); } else { EntityTable.this.rowChangeListener.rowChanged(null); } } else { logger.warn("no row change listener exists"); } } catch (Exception e) { logger.error("{} {}", this.getClass().getCanonicalName(), e.getMessage()); throw e; } } }); } public void superChangeVariables(final Object source, final Map<String, Object> variables) { } /** * Hooking this allows us to veto the user selecting a new row. if there is * a rowChangeListener we will prevent the row change. it's up to the * listener to callback on superChangeVariables to perform the row change if * row change should be allowed. */ @Override public void changeVariables(final Object source, final Map<String, Object> variables) { try { if (variables.containsKey("selected")) { if (EntityTable.this.rowChangeListener != null) { EntityTable.this.rowChangeListener.allowRowChange(new RowChangeCallback() { @Override public void allowRowChange() { EntityTable.super.changeVariables(source, variables); } }); markAsDirty(); } else { EntityTable.super.changeVariables(source, variables); } } else { super.changeVariables(source, variables); } } catch (Exception e) { ErrorWindow.showErrorWindow(e); } } @Override public EntityItem<E> getCurrent() { Object entityId = this.getValue(); EntityItem<E> entity = null; if ((entityId instanceof UUID)) { logger.warn("UUID here, this may be ok and even common when in a child crud."); } if (entityId != null)// && !(entityId instanceof UUID)) { try { if ((entityId instanceof UUID)) { if (entityContainer.getItemIds().contains(entityId)) { entity = this.entityContainer.getItem(entityId); } else { Exception e = new Exception("Trying to look up a non existent UUID"); logger.error(e, e); } } else { entity = this.entityContainer.getItem(entityId); } } catch (Exception e) { logger.warn(e, e); } } return entity; } /** * This nasty piece of work exists to stop the following exception being * thrown. java.lang.IllegalArgumentException: wrong number of arguments * sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) * sun.reflect.NativeMethodAccessorImpl * .invoke(NativeMethodAccessorImpl.java:57) * sun.reflect.DelegatingMethodAccessorImpl * .invoke(DelegatingMethodAccessorImpl.java:43) * java.lang.reflect.Method.invoke(Method.java:606) * com.vaadin.addon.jpacontainer * .metadata.ClassMetadata.getPropertyValue(ClassMetadata.java:168) * com.vaadin.addon.jpacontainer.metadata.ClassMetadata.getPropertyValue( * ClassMetadata.java:343) * com.vaadin.addon.jpacontainer.PropertyList.getPropertyValue * (PropertyList.java:677) * com.vaadin.addon.jpacontainer.JPAContainerItem$ItemProperty * .getRealValue(JPAContainerItem.java:176) * com.vaadin.addon.jpacontainer.JPAContainerItem$ItemProperty * .getValue(JPAContainerItem.java:163) * com.vaadin.ui.Table.formatPropertyValue(Table.java:4012) * com.vaadin.ui.Table.getPropertyValue(Table.java:3956) * com.vaadin.ui.Table.parseItemIdToCells(Table.java:2308) * com.vaadin.ui.Table.getVisibleCellsNoCache(Table.java:2147) * com.vaadin.ui.Table.refreshRenderedCells(Table.java:1668) * com.vaadin.ui.Table.enableContentRefreshing(Table.java:3143) * com.vaadin.ui.Table.setContainerDataSource(Table.java:2712) * com.vaadin.ui.Table.setContainerDataSource(Table.java:2653) * au.org.scoutmaster.views.ContactTable.init(ContactTable.java:46) */ @Override protected String formatPropertyValue(Object rowId, Object colId, Property<?> property) { if (property.getType() == Set.class) { return null; } try { property.getValue(); } catch (Exception e) { return null; } String ret = null; try { ret = super.formatPropertyValue(rowId, colId, property); } catch (Exception e) { logger.error("value: " + property.getValue() + " type: " + property.getType(), e); ret = e.getMessage(); } return ret; } @Override public void addGeneratedColumn(Object id, ColumnGenerator generatedColumn) { super.addGeneratedColumn(id, generatedColumn); } @Override public void setConverter(String name, Converter<String, ?> converter) { super.setConverter(name, converter); } @Override public void setColumnCollapsed(String name, boolean collapsed) { super.setColumnCollapsed(name, collapsed); } /** * When {@link #select(Object)} is called, * {@link RowChangeListener#allowRowChange(RowChangeCallback)} does not get * called. Call this method if you wish to check whether a row change is * allowed before selecting a new row. */ public void selectAndCheckRowChangeAllowed(final Object itemId) { if (EntityTable.this.rowChangeListener != null) { EntityTable.this.rowChangeListener.allowRowChange(new RowChangeCallback() { @Override public void allowRowChange() { EntityTable.super.select(itemId); } }); } else { select(itemId); } } /** * Adds a listener to select the right clicked item in the table. This is * needed by ContextMenus. */ private void addRightClickSelect() { this.addItemClickListener(new ItemClickListener() { private static final long serialVersionUID = 1L; @Override public void itemClick(ItemClickEvent event) { if (event.getButton() == MouseButton.RIGHT) { EntityTable.this.setValue(event.getItemId()); } } }); } }