Java tutorial
/** * Copyright 2014 The Kuali Foundation Licensed under the * Educational Community 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.osedu.org/licenses/ECL-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. * * Created by venkat on 9/3/14 */ package org.kuali.student.cm.course.modifiers; import org.apache.commons.lang.StringUtils; import org.kuali.rice.krad.uif.UifConstants; import org.kuali.rice.krad.uif.UifPropertyPaths; import org.kuali.rice.krad.uif.component.Component; import org.kuali.rice.krad.uif.container.CollectionGroup; import org.kuali.rice.krad.uif.container.Group; import org.kuali.rice.krad.uif.element.Header; import org.kuali.rice.krad.uif.field.DataField; import org.kuali.rice.krad.uif.field.DataFieldBase; import org.kuali.rice.krad.uif.field.Field; import org.kuali.rice.krad.uif.field.SpaceField; import org.kuali.rice.krad.uif.layout.GridLayoutManager; import org.kuali.rice.krad.uif.lifecycle.ViewLifecycle; import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleUtils; import org.kuali.rice.krad.uif.modifier.ComparableInfo; import org.kuali.rice.krad.uif.modifier.CompareFieldCreateModifier; import org.kuali.rice.krad.uif.util.ComponentFactory; import org.kuali.rice.krad.uif.util.ComponentUtils; import org.kuali.rice.krad.uif.util.ObjectPropertyUtils; import org.kuali.rice.krad.uif.view.ExpressionEvaluator; import org.kuali.rice.krad.uif.view.View; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Modifier which runs at APPLY_MODEL lifecycle phase and it clones all the items in a group and sets the binding path * accordingly. Also, it sets the highlight CSS if data is different between the two group items. * * @author Kuali Student Team */ public class CMCourseFieldCompareModifier extends CompareFieldCreateModifier { /** * Properties which should not get highlighting or compare-to data. */ private List<String> excludeProperties = new ArrayList<>(); /** * This method clones all the items in a group, sets proper binding path and mark for hightlight if the model * data is different. This method is a direct copy of the base class method but has a lot of tweaks. * * @see CompareFieldCreateModifier#performModification(Object, org.kuali.rice.krad.uif.component.Component) * @param model * @param component */ @Override public void performModification(Object model, Component component) { if ((component != null) && !(component instanceof Group)) { throw new IllegalArgumentException( "Compare field initializer only support Group components, found type: " + component.getClass()); } if (component == null) { return; } Group group = (Group) component; // list to hold the generated compare items List<Component> comparisonItems = new ArrayList<Component>(); // sort comparables by their order property List<ComparableInfo> groupComparables = (List<ComparableInfo>) ComponentUtils.sort(getComparables(), getDefaultOrderSequence()); // evaluate expressions on comparables Map<String, Object> context = new HashMap<String, Object>(); View view = ViewLifecycle.getView(); Map<String, Object> viewContext = view.getContext(); if (viewContext != null) { context.putAll(view.getContext()); } context.put(UifConstants.ContextVariableNames.COMPONENT, component); ExpressionEvaluator expressionEvaluator = ViewLifecycle.getExpressionEvaluator(); for (ComparableInfo comparable : groupComparables) { expressionEvaluator.evaluateExpressionsOnConfigurable(view, comparable, context); } // generate compare header if (isGenerateCompareHeaders()) { // add space field for label column SpaceField spaceField = ComponentFactory.getSpaceField(); comparisonItems.add(spaceField); for (ComparableInfo comparable : groupComparables) { Header compareHeaderField = ComponentUtils.copy(getHeaderFieldPrototype(), comparable.getIdSuffix()); compareHeaderField.setHeaderText(comparable.getHeaderText()); comparisonItems.add(compareHeaderField); } // if group is using grid layout, make first row a header if (group.getLayoutManager() instanceof GridLayoutManager) { ((GridLayoutManager) group.getLayoutManager()).setRenderFirstRowHeader(true); } } // find the comparable to use for comparing value changes (if // configured) boolean performValueChangeComparison = false; String compareValueObjectBindingPath = null; for (ComparableInfo comparable : groupComparables) { if (comparable.isCompareToForValueChange()) { performValueChangeComparison = true; compareValueObjectBindingPath = comparable.getBindingObjectPath(); } } // generate the compare items from the configured group int index = 0; List<String> rowCssClasses = new ArrayList<>(); for (Component item : group.getItems()) { // Determine if this property is in the exclude list. boolean excluded = false; if (item instanceof DataFieldBase) { String bindingPath = ((DataFieldBase) item).getBindingInfo().getBindingPath(); if (StringUtils.isNotBlank(bindingPath)) { for (String exclude : getExcludeProperties()) { if (bindingPath.endsWith(exclude)) { excluded = true; break; } } } } String rowCSS = ""; int defaultSuffix = 0; boolean suppressLabel = false; for (ComparableInfo comparable : groupComparables) { String idSuffix = comparable.getIdSuffix(); if (StringUtils.isBlank(idSuffix)) { idSuffix = UifConstants.IdSuffixes.COMPARE + defaultSuffix; } Component compareItem = ComponentUtils.copy(item, idSuffix); ComponentUtils.setComponentPropertyDeep(compareItem, UifPropertyPaths.BIND_OBJECT_PATH, comparable.getBindingObjectPath()); List<CollectionGroup> collectionGroups = ViewLifecycleUtils.getElementsOfTypeDeep(compareItem, CollectionGroup.class); for (CollectionGroup collectionGroup : collectionGroups) { updateCollectionGroupBindingPath(collectionGroup, comparable.getBindingObjectPath()); } if (comparable.isReadOnly()) { compareItem.setReadOnly(true); if (compareItem.getPropertyExpressions().containsKey("readOnly")) { compareItem.getPropertyExpressions().remove("readOnly"); } } // label will be enabled for first comparable only if (suppressLabel && (compareItem instanceof Field)) { ((Field) compareItem).getFieldLabel().setRender(false); } // Do value comparison if, among other things, this component hasn't been excluded. if (performValueChangeComparison && comparable.isHighlightValueChange() && !comparable.isCompareToForValueChange() && !excluded) { boolean valueChanged = performValueComparison(group, compareItem, model, compareValueObjectBindingPath); if (valueChanged) { rowCSS = "cm-compare-highlighter"; } } // If this is an excluded component then don't display the right-column/compare-to data. // Typically it won't exist but if it does it won't be displayed. if (excluded) { item.setStyle("display: none;"); } comparisonItems.add(compareItem); defaultSuffix++; suppressLabel = true; } rowCssClasses.add(rowCSS); index++; } if (group.getLayoutManager() instanceof GridLayoutManager) { ((GridLayoutManager) group.getLayoutManager()).setRowCssClasses(rowCssClasses); } // update the group's list of components group.setItems(comparisonItems); } /** * This method updates the binding path for all the items in a collection group and all its subcolletions * recursively. * * @param collectionGroup * @param bindingPath */ protected void updateCollectionGroupBindingPath(CollectionGroup collectionGroup, String bindingPath) { ComponentUtils.setComponentPropertyDeep(collectionGroup, UifPropertyPaths.BIND_OBJECT_PATH, bindingPath); ComponentUtils.setComponentPropertyDeep(collectionGroup, "fieldBindingObjectPath", bindingPath); List<CollectionGroup> subCollection = collectionGroup.getSubCollections(); for (CollectionGroup subCollectionGroup1 : subCollection) { updateCollectionGroupBindingPath(subCollectionGroup1, bindingPath); } List<? extends Component> dataFields = collectionGroup.getItems(); for (Component field : dataFields) { ComponentUtils.setComponentPropertyDeep(field, UifPropertyPaths.BIND_OBJECT_PATH, bindingPath); ComponentUtils.setComponentPropertyDeep(field, "fieldBindingObjectPath", bindingPath); if (field instanceof DataField) { ((DataField) field).getBindingInfo().setBindingObjectPath(bindingPath); } } } /** * Copy of the base class implementation but we dont need setting 'showChangeIcon()' JS as the default * implementation does. * * @param group * @param compareItem * @param model * @param compareValueObjectBindingPath * @return */ @Override protected boolean performValueComparison(Group group, Component compareItem, Object model, String compareValueObjectBindingPath) { // get any attribute fields for the item so we can compare the values List<DataField> itemFields = ViewLifecycleUtils.getElementsOfTypeDeep(compareItem, DataField.class); boolean valueChanged = false; for (DataField field : itemFields) { String fieldBindingPath = field.getBindingInfo().getBindingPath(); Object fieldValue = ObjectPropertyUtils.getPropertyValue(model, fieldBindingPath); String compareBindingPath = StringUtils.replaceOnce(fieldBindingPath, field.getBindingInfo().getBindingObjectPath(), compareValueObjectBindingPath); Object compareValue = ObjectPropertyUtils.getPropertyValue(model, compareBindingPath); if (!((fieldValue == null) && (compareValue == null))) { // if one is null then value changed if ((fieldValue == null) || (compareValue == null)) { valueChanged = true; } else { // both not null, compare values valueChanged = !fieldValue.equals(compareValue); } } } return valueChanged; } /** * @see #setExcludeProperties(java.util.List) * @return */ public List<String> getExcludeProperties() { return excludeProperties; } /** * List of fields to exclude for comparsion and marking the fields for hightlight. * @param excludeProperties */ public void setExcludeProperties(List<String> excludeProperties) { this.excludeProperties = excludeProperties; } }