View Javadoc
1   /**
2    * Copyright 2005-2016 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.uif.mock;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.core.api.data.DataType;
20  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
21  import org.kuali.rice.krad.uif.UifConstants;
22  import org.kuali.rice.krad.uif.UifPropertyPaths;
23  import org.kuali.rice.krad.uif.component.Component;
24  import org.kuali.rice.krad.uif.component.DataBinding;
25  import org.kuali.rice.krad.uif.container.CollectionGroup;
26  import org.kuali.rice.krad.uif.control.CheckboxControl;
27  import org.kuali.rice.krad.uif.element.Action;
28  import org.kuali.rice.krad.uif.field.DataField;
29  import org.kuali.rice.krad.uif.field.InputField;
30  import org.kuali.rice.krad.uif.lifecycle.ViewLifecycleUtils;
31  import org.kuali.rice.krad.uif.util.ComponentUtils;
32  import org.kuali.rice.krad.uif.util.LifecycleElement;
33  import org.kuali.rice.krad.uif.util.ObjectPropertyUtils;
34  import org.kuali.rice.krad.uif.view.FormView;
35  
36  import java.util.ArrayList;
37  import java.util.Collection;
38  import java.util.List;
39  
40  /**
41   * View class for developing UI mocks.
42   *
43   * <p>Automatically binds data binding components to a dummy map property on the mock form.</p>
44   *
45   * @author Kuali Rice Team (rice.collab@kuali.org)
46   */
47  @BeanTag(name = "mockView", parent = "Uif-MockView")
48  public class MockView extends FormView {
49      private static final long serialVersionUID = 3075358370551614649L;
50  
51      private static final String DATA_BINDING_PATH = "data";
52      private static final String BOOLEAN_DATA_BINDING_PATH = "booleanData";
53  
54      public MockView() {
55          super();
56      }
57  
58      /**
59       * Adjusts the binding paths for data binding components to match the generic data map.
60       *
61       * {@inheritDoc}
62       */
63      @Override
64      public void performInitialization(Object model) {
65          super.performInitialization(model);
66  
67          DynaForm dynaForm = (DynaForm) model;
68  
69          List<DataBinding> bindingComponents = ViewLifecycleUtils.getElementsOfTypeDeep(this, DataBinding.class);
70          for (DataBinding bindingComponent : bindingComponents) {
71              adjustBindingPath(bindingComponent);
72          }
73  
74          List<CollectionGroup> collectionGroups = ViewLifecycleUtils.getElementsOfTypeDeep(this, CollectionGroup.class);
75          for (CollectionGroup collectionGroup : collectionGroups) {
76              mockCollectionGroup(collectionGroup, dynaForm, null);
77          }
78      }
79  
80      /**
81       * Creates sample data for read only data fields and defaults actions to call the refresh method.
82       *
83       * {@inheritDoc}
84       */
85      @Override
86      public void performFinalize(Object model, LifecycleElement parent) {
87          super.performFinalize(model, parent);
88  
89          List<DataField> dataFields = ViewLifecycleUtils.getElementsOfTypeDeep(this, DataField.class);
90          for (DataField dataField : dataFields) {
91              if ((!(dataField instanceof InputField)) && (dataField.getDefaultValue() == null)) {
92                  createSampleData(dataField, model);
93              }
94          }
95  
96          List<Action> actions = ViewLifecycleUtils.getElementsOfTypeDeep(this, Action.class);
97          for (Action action : actions) {
98              if (StringUtils.isBlank(action.getMethodToCall())) {
99                  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 }