package net.techreadiness.ui.tags.datagrid; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.util.List; import java.util.Map; import org.apache.commons.lang3.StringUtils; import com.google.common.base.Predicate; import com.google.common.collect.Maps; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.util.TextParseUtil; import com.opensymphony.xwork2.util.ValueStack; public class RowInfo<T> { private final DataGridTag<T> dataGrid; private final T row; private final boolean editMode; private final String rowId; private final boolean rowSelected; private Map<String, List<String>> fieldErrors; private boolean rowInError; private T errorRow; private boolean selectionDisabled = false; private String defaultClass = "standard-row"; private String selectedClass = "rowSelected"; private String errorClass = "rowErrors"; private String inlineEditableClass = "inlineEditable"; private String inlineEditingClass = "inlineEdit"; private String fieldNamePrefix; private boolean multiEdit; public RowInfo(DataGridTag<T> dataGrid, T row) { ValueStack valueStack = ActionContext.getContext().getValueStack(); this.dataGrid = dataGrid; this.editMode = dataGrid.isEditMode(row); this.rowId = dataGrid.getRowId(row); this.rowSelected = dataGrid.isRowSelected(row); this.multiEdit = dataGrid.isMultiEditable(); this.row = row; if (this.dataGrid.getSelectedDisabledTest() != null) {// this only gets // run if the // datagrid has // the attribute try { valueStack.push(row); Map<String, Object> pushVals = Maps.newHashMap(); pushVals.put(this.dataGrid.getVar(), row); try { valueStack.push(pushVals); if ("true".equals(TextParseUtil.translateVariables('%', this.dataGrid.getSelectedDisabledTest(), valueStack))) { selectionDisabled = true; } } finally { valueStack.pop(); } } finally { valueStack.pop(); } } if (StringUtils.isEmpty(dataGrid.getFieldName())) { fieldNamePrefix = dataGrid.getVar(); setErrorInfo(); } else { try { valueStack.push(row); Map<String, Object> rowMap = Maps.newHashMap(); rowMap.put(dataGrid.getVar(), row); try { valueStack.push(rowMap); fieldNamePrefix = TextParseUtil.translateVariables('%', dataGrid.getFieldName(), valueStack); setErrorInfo(); } finally { valueStack.pop(); } } finally { valueStack.pop(); } } } public boolean isGroupChanged() { if (StringUtils.isBlank(dataGrid.getGroupExpression())) { return true; } String currentGroupValue = TextParseUtil.translateVariables('%', StringUtils.defaultString(dataGrid.getGroupExpression()), ActionContext.getContext().getValueStack()); boolean groupChanged = !currentGroupValue.equals(dataGrid.getPrevGroupValue()); dataGrid.setPrevGroupValue(currentGroupValue); return groupChanged; } @SuppressWarnings({ "unchecked", "rawtypes" }) private void setErrorInfo() { ValueStack valueStack = ActionContext.getContext().getValueStack(); Map<String, List<String>> errors = (Map<String, List<String>>) valueStack.findValue("fieldErrors"); fieldErrors = getErrorsForCurrentRow(errors); this.rowInError = editMode && fieldErrors != null && !fieldErrors.isEmpty(); if (rowInError) { T errorData = (T) valueStack.findValue(fieldNamePrefix); if (row instanceof Map) { Map<?, ?> rowData = (Map<?, ?>) row; rowData.putAll((Map) errorData); errorRow = (T) rowData; } else { merge(errorData, row); this.errorRow = row; } } else { this.errorRow = row; } } private void merge(T target, T destination) { try { BeanInfo beanInfo = Introspector.getBeanInfo(target.getClass()); // Iterate over all the attributes for (PropertyDescriptor descriptor : beanInfo.getPropertyDescriptors()) { // Only copy writable attributes if (descriptor.getWriteMethod() != null) { Object originalValue = descriptor.getReadMethod().invoke(target); // Only copy values values where the destination values is // null if (originalValue == null) { Object defaultValue = descriptor.getReadMethod().invoke(destination); descriptor.getWriteMethod().invoke(target, defaultValue); } } } } catch (Exception e) { throw new RuntimeException(e); } } public boolean isRowInError() { return rowInError; } public String getRowClass() { StringBuilder rowClass = new StringBuilder(); rowClass.append(defaultClass); rowClass.append(" ").append(getEditClass()); rowClass.append(" ").append(getDisplayClass()); return rowClass.toString(); } public String getEditClass() { if (editMode && !multiEdit) { if (isRowInError()) { return errorClass; } return inlineEditingClass; } else if (dataGrid.isInlineEditable() && !dataGrid.isInlineEditing()) { return inlineEditableClass; } else { return ""; } } public String getDisplayClass() { if (rowSelected) { return selectedClass; } return ""; } public String getColumnEditClass() { if (editMode) { return inlineEditingClass; } else if (dataGrid.isInlineEditable() && !dataGrid.isInlineEditing()) { return inlineEditableClass; } return ""; } public T getRow() { return row; } public String getDefaultClass() { return defaultClass; } public void setDefaultClass(String defaultClass) { this.defaultClass = defaultClass; } public String getSelectedClass() { return selectedClass; } public void setSelectedClass(String selectedClass) { this.selectedClass = selectedClass; } public String getErrorClass() { return errorClass; } public void setErrorClass(String errorClass) { this.errorClass = errorClass; } public String getInlineEditableClass() { return inlineEditableClass; } public void setInlineEditableClass(String inlineEditableClass) { this.inlineEditableClass = inlineEditableClass; } public String getInlineEditingClass() { return inlineEditingClass; } public void setInlineEditingClass(String inlineEditingClass) { this.inlineEditingClass = inlineEditingClass; } public DataGridTag<T> getDataGrid() { return dataGrid; } public boolean isEditMode() { return editMode; } public String getRowId() { return rowId; } public boolean isRowSelected() { return rowSelected; } public Map<?, ?> getFieldErrors() { return fieldErrors; } public T getErrorRow() { return errorRow; } protected Map<String, List<String>> getErrorsForCurrentRow(Map<String, List<String>> errors) { return Maps.filterKeys(errors, new FieldErrorFilter()); } public void setSelectionDisabled(boolean selectionDisabled) { this.selectionDisabled = selectionDisabled; } public boolean isSelectionDisabled() { return selectionDisabled; } class FieldErrorFilter implements Predicate<String> { @Override public boolean apply(String input) { return StringUtils.startsWith(input, fieldNamePrefix); } } }