View Javadoc

1   /**
2    * Copyright 2005-2014 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.control;
17  
18  import org.kuali.rice.core.api.util.ConcreteKeyValue;
19  import org.kuali.rice.core.api.util.KeyValue;
20  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
21  import org.kuali.rice.krad.uif.UifConstants;
22  import org.kuali.rice.krad.uif.component.Component;
23  import org.kuali.rice.krad.uif.container.Container;
24  import org.kuali.rice.krad.uif.element.Message;
25  import org.kuali.rice.krad.uif.field.InputField;
26  import org.kuali.rice.krad.uif.util.ComponentUtils;
27  import org.kuali.rice.krad.uif.view.ExpressionEvaluator;
28  import org.kuali.rice.krad.uif.util.ComponentFactory;
29  import org.kuali.rice.krad.uif.util.ExpressionUtils;
30  import org.kuali.rice.krad.uif.util.KeyMessage;
31  import org.kuali.rice.krad.uif.util.UrlInfo;
32  import org.kuali.rice.krad.uif.util.UifKeyValueLocation;
33  import org.kuali.rice.krad.uif.view.View;
34  
35  import java.util.ArrayList;
36  import java.util.List;
37  
38  /**
39   * Base class for controls that accept/display multiple values
40   *
41   * @author Kuali Rice Team (rice.collab@kuali.org)
42   */
43  public abstract class MultiValueControlBase extends ControlBase implements MultiValueControl {
44      private static final long serialVersionUID = -8691367056245775455L;
45  
46      private List<KeyValue> options;
47      private List<KeyMessage> richOptions;
48      private List<Component> inlineComponents;
49  
50      private boolean locationSelect = false;
51  
52      public MultiValueControlBase() {
53          super();
54      }
55  
56      /**
57       * Process rich message content that may be in the options, by creating and initializing the richOptions
58       *
59       * @see org.kuali.rice.krad.uif.component.ComponentBase#performApplyModel(org.kuali.rice.krad.uif.view.View,
60       *      Object, org.kuali.rice.krad.uif.component.Component)
61       */
62      @Override
63      public void performApplyModel(View view, Object model, Component parent) {
64          super.performApplyModel(view, model, parent);
65  
66          if (options != null && richOptions == null) {
67              richOptions = new ArrayList<KeyMessage>();
68  
69              for (KeyValue option : options) {
70                  Message message = ComponentFactory.getMessage();
71                  view.assignComponentIds(message);
72                  message.setMessageText(option.getValue());
73                  message.setInlineComponents(inlineComponents);
74                  message.setGenerateSpan(false);
75  
76                  view.getViewHelperService().performComponentInitialization(view, model, message);
77                  richOptions.add(new KeyMessage(option.getKey(), option.getValue(), message));
78              }
79          }
80      }
81  
82      /**
83       * Adds appropriate parent data to inputs internal to the controls that may be in rich content of options
84       *
85       * @see org.kuali.rice.krad.uif.component.Component#performFinalize(org.kuali.rice.krad.uif.view.View, Object,
86       *      org.kuali.rice.krad.uif.component.Component)
87       */
88      @Override
89      public void performFinalize(View view, Object model, Component parent) {
90          super.performFinalize(view, model, parent);
91  
92          ExpressionEvaluator expressionEvaluator = view.getViewHelperService().getExpressionEvaluator();
93  
94          if (options != null && !options.isEmpty()) {
95              for (KeyValue option : options) {
96                  if (option instanceof UifKeyValueLocation) {
97                      locationSelect = true;
98  
99                      UrlInfo url = ((UifKeyValueLocation) option).getLocation();
100 
101                     ExpressionUtils.populatePropertyExpressionsFromGraph(url, false);
102                     expressionEvaluator.evaluateExpressionsOnConfigurable(view, url, view.getContext());
103                 }
104             }
105         }
106 
107         if (richOptions == null || richOptions.isEmpty()) {
108             return;
109         }
110 
111         //Messages included in options which have have rich message content need to be aware of their parent for
112         //validation purposes
113         for (KeyMessage richOption : richOptions) {
114             List<Component> components = richOption.getMessage().getMessageComponentStructure();
115 
116             if (components != null && !components.isEmpty()) {
117                 for (Component c : components) {
118                     if (c instanceof Container || c instanceof InputField) {
119                         c.addDataAttribute(UifConstants.DataAttributes.PARENT, parent.getId());
120                     }
121                 }
122             }
123         }
124 
125     }
126 
127     /**
128      * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
129      */
130     @Override
131     public List<Component> getComponentsForLifecycle() {
132         List<Component> components = super.getComponentsForLifecycle();
133 
134         if (richOptions != null) {
135             for (KeyMessage richOption : richOptions) {
136                 components.add(richOption.getMessage());
137             }
138         }
139 
140         return components;
141     }
142 
143     /**
144      * @see MultiValueControl#getOptions()
145      */
146     @BeanTagAttribute(name = "options", type = BeanTagAttribute.AttributeType.LISTBEAN)
147     public List<KeyValue> getOptions() {
148         return this.options;
149     }
150 
151     /**
152      * @see MultiValueControl#setOptions(java.util.List<org.kuali.rice.core.api.util.KeyValue>)
153      */
154     public void setOptions(List<KeyValue> options) {
155         this.options = options;
156     }
157 
158     /**
159      * Gets the inlineComponents which represent components that can be referenced in an option's value
160      * by index
161      *
162      * @return the components that can be used in rich values of options
163      */
164     @BeanTagAttribute(name = "inlineComponents", type = BeanTagAttribute.AttributeType.LISTBEAN)
165     public List<Component> getInlineComponents() {
166         return inlineComponents;
167     }
168 
169     /**
170      * Sets the inlineComponents which represent components that can be referenced in an option's value
171      * by index
172      *
173      * @param inlineComponents
174      */
175     public void setInlineComponents(List<Component> inlineComponents) {
176         this.inlineComponents = inlineComponents;
177     }
178 
179     /**
180      * @see MultiValueControl#getRichOptions()
181      */
182     public List<KeyMessage> getRichOptions() {
183         return richOptions;
184     }
185 
186     /**
187      * Sets the richOptions.  This will always override/ignore options if set.
188      *
189      * <p><b>Messages MUST be defined</b> when using this setter, do not use this setter for most cases
190      * as setting options through setOptions, with a richMessage value, is appropriate in MOST cases.  This
191      * setter is only available for full control.</p>
192      *
193      * @param richOptions with their messages predefined
194      */
195     public void setRichOptions(List<KeyMessage> richOptions) {
196         this.richOptions = richOptions;
197     }
198 
199     /**
200      * If true, this select represents a location select (navigate on select of option)
201      *
202      * @return true if this is a location select
203      */
204     public boolean isLocationSelect() {
205         return locationSelect;
206     }
207 
208     /**
209      * Sets the location select (navigate on select of option)
210      *
211      * @param locationSelect
212      */
213     protected void setLocationSelect(boolean locationSelect) {
214         this.locationSelect = locationSelect;
215     }
216 
217     /**
218      * @see org.kuali.rice.krad.uif.component.ComponentBase#copy()
219      */
220     @Override
221     protected <T> void copyProperties(T component) {
222         super.copyProperties(component);
223         MultiValueControlBase multiValueControlBaseCopy = (MultiValueControlBase) component;
224 
225         try {
226             if (options != null) {
227                 List<KeyValue> optionsCopy = new ArrayList<KeyValue>();
228                 for (KeyValue option : options) {
229 
230                     KeyValue keyValue = null;
231                     if (option != null) {
232                         Class<? extends KeyValue> optionClass = option.getClass();
233                         keyValue = optionClass.getDeclaredConstructor(String.class, String.class).newInstance(
234                                 option.getKey(), option.getValue());
235                         if (keyValue instanceof UifKeyValueLocation) {
236                             ((UifKeyValueLocation) keyValue).setLocation(
237                                     (UrlInfo) ((UifKeyValueLocation) option).getLocation().copy());
238                         }
239                     }
240 
241                     optionsCopy.add(keyValue);
242                 }
243                 multiValueControlBaseCopy.setOptions(optionsCopy);
244             }
245         } catch (Exception e) {
246             throw new RuntimeException("Failed to copy options in MultiValueControlBase", e);
247         }
248 
249         if (richOptions != null) {
250             List<KeyMessage> richOptionsCopy = new ArrayList<KeyMessage>();
251             for (KeyMessage richOption : richOptions) {
252                 KeyMessage keyMessage = new KeyMessage(richOption.getKey(), richOption.getValue(),
253                         richOption.getMessage());
254                 richOptionsCopy.add(keyMessage);
255             }
256             multiValueControlBaseCopy.setRichOptions(richOptionsCopy);
257         }
258 
259         if (inlineComponents != null) {
260             List<Component> inlineComponentsCopy = new ArrayList<Component>();
261             for (Component inlineComponent : inlineComponents) {
262                 inlineComponentsCopy.add((Component) inlineComponent.copy());
263             }
264             multiValueControlBaseCopy.setInlineComponents(inlineComponentsCopy);
265         }
266 
267         multiValueControlBaseCopy.setLocationSelect(this.locationSelect);
268     }
269 }