001/** 002 * Copyright 2005-2018 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kuali.rice.krad.uif.mock; 017 018import org.apache.commons.lang.StringUtils; 019import org.kuali.rice.core.api.data.DataType; 020import org.kuali.rice.krad.datadictionary.parse.BeanTag; 021import org.kuali.rice.krad.uif.UifConstants; 022import org.kuali.rice.krad.uif.UifPropertyPaths; 023import org.kuali.rice.krad.uif.component.Component; 024import org.kuali.rice.krad.uif.component.DataBinding; 025import org.kuali.rice.krad.uif.container.CollectionGroup; 026import org.kuali.rice.krad.uif.control.CheckboxControl; 027import org.kuali.rice.krad.uif.element.Action; 028import org.kuali.rice.krad.uif.field.DataField; 029import org.kuali.rice.krad.uif.field.InputField; 030import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleUtils; 031import org.kuali.rice.krad.uif.util.ComponentUtils; 032import org.kuali.rice.krad.uif.util.LifecycleElement; 033import org.kuali.rice.krad.uif.util.ObjectPropertyUtils; 034import org.kuali.rice.krad.uif.view.FormView; 035 036import java.util.ArrayList; 037import java.util.Collection; 038import java.util.List; 039 040/** 041 * View class for developing UI mocks. 042 * 043 * <p>Automatically binds data binding components to a dummy map property on the mock form.</p> 044 * 045 * @author Kuali Rice Team (rice.collab@kuali.org) 046 */ 047@BeanTag(name = "mockView", parent = "Uif-MockView") 048public class MockView extends FormView { 049 private static final long serialVersionUID = 3075358370551614649L; 050 051 private static final String DATA_BINDING_PATH = "data"; 052 private static final String BOOLEAN_DATA_BINDING_PATH = "booleanData"; 053 054 public MockView() { 055 super(); 056 } 057 058 /** 059 * Adjusts the binding paths for data binding components to match the generic data map. 060 * 061 * {@inheritDoc} 062 */ 063 @Override 064 public void performInitialization(Object model) { 065 super.performInitialization(model); 066 067 DynaForm dynaForm = (DynaForm) model; 068 069 List<DataBinding> bindingComponents = ViewLifecycleUtils.getElementsOfTypeDeep(this, DataBinding.class); 070 for (DataBinding bindingComponent : bindingComponents) { 071 adjustBindingPath(bindingComponent); 072 } 073 074 List<CollectionGroup> collectionGroups = ViewLifecycleUtils.getElementsOfTypeDeep(this, CollectionGroup.class); 075 for (CollectionGroup collectionGroup : collectionGroups) { 076 mockCollectionGroup(collectionGroup, dynaForm, null); 077 } 078 } 079 080 /** 081 * Creates sample data for read only data fields and defaults actions to call the refresh method. 082 * 083 * {@inheritDoc} 084 */ 085 @Override 086 public void performFinalize(Object model, LifecycleElement parent) { 087 super.performFinalize(model, parent); 088 089 List<DataField> dataFields = ViewLifecycleUtils.getElementsOfTypeDeep(this, DataField.class); 090 for (DataField dataField : dataFields) { 091 if ((!(dataField instanceof InputField)) && (dataField.getDefaultValue() == null)) { 092 createSampleData(dataField, model); 093 } 094 } 095 096 List<Action> actions = ViewLifecycleUtils.getElementsOfTypeDeep(this, Action.class); 097 for (Action action : actions) { 098 if (StringUtils.isBlank(action.getMethodToCall())) { 099 action.setMethodToCall(UifConstants.MethodToCallNames.REFRESH); 100 } 101 } 102 } 103 104 /** 105 * Adjusts the binding path for the given component to match the generic data map (or boolean data map). 106 * 107 * @param bindingComponent data binding component to adjust path for 108 */ 109 protected void adjustBindingPath(DataBinding bindingComponent) { 110 boolean isBooleanDataType = false; 111 112 if (bindingComponent instanceof InputField) { 113 InputField inputField = (InputField) bindingComponent; 114 if ((inputField.getDataType() != null) && inputField.getDataType().equals(DataType.BOOLEAN)) { 115 isBooleanDataType = true; 116 } else if ((inputField.getControl() != null) && (inputField.getControl() instanceof CheckboxControl)) { 117 isBooleanDataType = true; 118 } 119 } 120 121 bindingComponent.getBindingInfo().setDefaults(this, bindingComponent.getPropertyName()); 122 123 if (isBooleanDataType) { 124 bindingComponent.getBindingInfo().setBindByNamePrefix(BOOLEAN_DATA_BINDING_PATH); 125 } else { 126 bindingComponent.getBindingInfo().setBindByNamePrefix(DATA_BINDING_PATH); 127 } 128 129 bindingComponent.getBindingInfo().setBindToMap(true); 130 } 131 132 /** 133 * Adjusts binding paths for the given collection group and sets the collection object class to be 134 * {@link org.kuali.rice.krad.uif.mock.DynaDataObject} 135 * 136 * @param collectionGroup collection group to adjust 137 * @param dynaForm form instance 138 * @param bindingPrefix prefix for the collection group (in case of a sub-collection) 139 */ 140 protected void mockCollectionGroup(CollectionGroup collectionGroup, DynaForm dynaForm, String bindingPrefix) { 141 collectionGroup.setCollectionObjectClass(DynaDataObject.class); 142 143 if (collectionGroup.getItems() != null) { 144 for (Component item : collectionGroup.getItems()) { 145 if (!(item instanceof DataBinding)) { 146 continue; 147 } 148 149 adjustBindingPath((DataBinding) item); 150 } 151 } 152 153 String collectionPropertyName = collectionGroup.getPropertyName(); 154 if (StringUtils.isNotBlank(bindingPrefix)) { 155 collectionPropertyName = bindingPrefix + "." + collectionPropertyName; 156 } 157 158 collectionGroup.getAddLineBindingInfo().setBindingPath( 159 UifPropertyPaths.NEW_COLLECTION_LINES + "[" + collectionPropertyName + "]"); 160 161 if (dynaForm.isInitialGetRequest()) { 162 createSampleLineData(collectionGroup, dynaForm); 163 } 164 165 if (collectionGroup.getSubCollections() != null) { 166 for (CollectionGroup subCollectionGroup : collectionGroup.getSubCollections()) { 167 subCollectionGroup.getBindingInfo().setBindingName( 168 DATA_BINDING_PATH + "[" + subCollectionGroup.getPropertyName() + "]"); 169 mockCollectionGroup(subCollectionGroup, dynaForm, collectionPropertyName); 170 } 171 } 172 } 173 174 /** 175 * Creates sample data for the giving binding component. 176 * 177 * @param bindingComponent component to create data for 178 * @param model form instance holding the view's data 179 */ 180 protected void createSampleData(DataBinding bindingComponent, Object model) { 181 String bindingPath = bindingComponent.getBindingInfo().getBindingPath(); 182 ObjectPropertyUtils.setPropertyValue(model, bindingPath, "data"); 183 } 184 185 /** 186 * Creates sample collection lines for the give collection group. 187 * 188 * @param collectionGroup collection group to create lines for 189 * @param model form instance holding the view's data 190 */ 191 protected void createSampleLineData(CollectionGroup collectionGroup, Object model) { 192 String bindingPath = collectionGroup.getBindingInfo().getBindingPath(); 193 194 Collection<DynaDataObject> collection = ObjectPropertyUtils.getPropertyValue(model, bindingPath); 195 196 if (collection == null) { 197 collection = new ArrayList<DynaDataObject>(); 198 ObjectPropertyUtils.setPropertyValue(model, bindingPath, collection); 199 } 200 201 collection.add(new DynaDataObject()); 202 collection.add(new DynaDataObject()); 203 } 204}