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