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}