View Javadoc

1   /**
2    * Copyright 2005-2012 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.element;
17  
18  import org.apache.commons.lang.StringUtils;
19  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
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.CollectionGroup;
24  import org.kuali.rice.krad.uif.container.Container;
25  import org.kuali.rice.krad.uif.container.PageGroup;
26  import org.kuali.rice.krad.uif.field.FieldGroup;
27  import org.kuali.rice.krad.uif.field.InputField;
28  import org.kuali.rice.krad.uif.layout.StackedLayoutManager;
29  import org.kuali.rice.krad.uif.layout.TableLayoutManager;
30  import org.kuali.rice.krad.uif.util.ScriptUtils;
31  import org.kuali.rice.krad.uif.view.View;
32  import org.kuali.rice.krad.util.GlobalVariables;
33  
34  import java.util.ArrayList;
35  import java.util.List;
36  
37  /**
38   * ValidationMessages for logic and options specific to groups
39   */
40  @BeanTag(name="groupValidationMessage")
41  public class GroupValidationMessages extends ValidationMessages {
42      private static final long serialVersionUID = -5389990220206079052L;
43  
44      private boolean displayFieldLabelWithMessages;
45      private boolean collapseAdditionalFieldLinkMessages;
46  
47      private static final String SECTION_TOKEN = "s$";
48      private static final String FIELDGROUP_TOKEN = "f$";
49  
50      @Override
51      /**
52       * Calls super and adds dataAttributes that are appropriate for group level validationMessages
53       * data.  This data is used by the validation framework clientside.
54       *
55       * Some special handling at this level includes retrieving the groups and fields generated by
56       * different collection layouts and handling page and fieldGroup scenarios slightly differently
57       * due to the nature of how they are built out in the js.
58       *
59       * @see krad.validate.js
60       */
61      public void generateMessages(boolean reset, View view, Object model, Component parent) {
62          super.generateMessages(reset, view, model, parent);
63  
64          Object parentContainer = parent.getContext().get(UifConstants.ContextVariableNames.PARENT);
65  
66          List<? extends Component> items = ((Container) parent).getItems();
67          boolean skipSections = false;
68  
69          //Handle the special CollectionGroup case by getting the StackedGroups and DataFields generated by them
70          if (parent instanceof CollectionGroup) {
71              if (((CollectionGroup) parent).getLayoutManager() instanceof StackedLayoutManager) {
72                  items = ((StackedLayoutManager) ((CollectionGroup) parent).getLayoutManager()).getStackedGroups();
73              } else if (((CollectionGroup) parent).getLayoutManager() instanceof TableLayoutManager) {
74                  items = ((TableLayoutManager) ((CollectionGroup) parent).getLayoutManager()).getDataFields();
75                  skipSections = true;
76              }
77          }
78  
79          List<String> sectionIds = new ArrayList<String>();
80          List<String> fieldOrder = new ArrayList<String>();
81          collectIdsFromItems(items, sectionIds, fieldOrder, skipSections);
82  
83          boolean pageLevel = false;
84          boolean forceShow = false;
85          if (parent instanceof PageGroup) {
86              pageLevel = true;
87              forceShow = true;
88              parent.addDataAttribute(UifConstants.DataAttributes.SERVER_MESSAGES,
89                      Boolean.toString(GlobalVariables.getMessageMap().hasMessages()));
90          } else if (parentContainer instanceof FieldGroup) {
91              //note this means container of the parent is a FieldGroup
92              forceShow = true;
93          }
94  
95          boolean hasMessages = false;
96          if(!this.getErrors().isEmpty() || !this.getWarnings().isEmpty() || !this.getInfos().isEmpty()){
97              hasMessages = true;
98          }
99          parent.addDataAttribute(UifConstants.DataAttributes.VALIDATION_MESSAGES, "{"
100                 + UifConstants.DataAttributes.SUMMARIZE + ":"
101                 + true
102                 + ","
103                 + UifConstants.DataAttributes.DISPLAY_MESSAGES + ":"
104                 + this.isDisplayMessages()
105                 + ","
106                 + UifConstants.DataAttributes.COLLAPSE_FIELD_MESSAGES + ":"
107                 + collapseAdditionalFieldLinkMessages
108                 + ","
109                 + UifConstants.DataAttributes.DISPLAY_LABEL + ":"
110                 + displayFieldLabelWithMessages
111                 + ","
112                 + UifConstants.DataAttributes.HAS_OWN_MESSAGES + ":"
113                 + hasMessages
114                 + ","
115                 + UifConstants.DataAttributes.PAGE_LEVEL + ":"
116                 + pageLevel
117                 + ","
118                 + UifConstants.DataAttributes.FORCE_SHOW + ":"
119                 + forceShow
120                 + ","
121                 + UifConstants.DataAttributes.SECTIONS + ":"
122                 + ScriptUtils.convertStringListToJsArray(sectionIds)
123                 + ","
124                 + UifConstants.DataAttributes.ORDER + ":"
125                 + ScriptUtils.convertStringListToJsArray(fieldOrder)
126                 + ","
127                 + UifConstants.DataAttributes.SERVER_ERRORS + ":"
128                 + ScriptUtils.convertStringListToJsArray(ScriptUtils.escapeHtml(this.getErrors()))
129                 + ","
130                 + UifConstants.DataAttributes.SERVER_WARNINGS + ":"
131                 + ScriptUtils.convertStringListToJsArray(ScriptUtils.escapeHtml(this.getWarnings()))
132                 + ","
133                 + UifConstants.DataAttributes.SERVER_INFO + ":"
134                 + ScriptUtils.convertStringListToJsArray(ScriptUtils.escapeHtml(this.getInfos()))
135                 + "}");
136     }
137 
138     /**
139      * Collects all the ids from the items passed into this method.
140      *
141      * <p>Puts the ids of items determined to be sections
142      * into the sectionIds list, and orders all items by the order they appear on the page in the order list with
143      * special identifiers
144      * to determine the type of item they are (used by the client js).  When skipSections is true do not
145      * include sectionIds found in the lists.</p>
146      *
147      * @param items items of the group
148      * @param sectionIds list to put section ids into
149      * @param order list to put order of ids into (both fields and sections)
150      * @param skipSections skip adding sections
151      */
152     protected void collectIdsFromItems(List<? extends Component> items, List<String> sectionIds, List<String> order,
153             boolean skipSections) {
154 
155         if (items != null) {
156             for (Component c : items) {
157                 if (c instanceof Container || c instanceof FieldGroup) {
158                     if (c instanceof FieldGroup) {
159                         if (!skipSections &&
160                                 ((FieldGroup) c).getFieldLabel().isRender() &&
161                                 !((FieldGroup) c).getFieldLabel().isHidden() &&
162                                 (StringUtils.isNotEmpty(((FieldGroup) c).getLabel()) || StringUtils.isNotEmpty(
163                                         ((FieldGroup) c).getFieldLabel().getLabelText()))) {
164                             sectionIds.add(c.getId());
165                             order.add(FIELDGROUP_TOKEN + c.getId());
166                             continue;
167                         } else {
168                             c = ((FieldGroup) c).getGroup();
169                             if (c == null) {
170                                 continue;
171                             }
172                         }
173                     }
174 
175                     //If any kind of header text is showing consider this group a section
176                     if (!skipSections
177                             && ((Container) c).getHeader() != null
178                             && ((Container) c).getHeader().isRender()
179                             && (StringUtils.isNotBlank(((Container) c).getHeader().getHeaderText()) || StringUtils
180                             .isNotBlank(c.getTitle()))) {
181                         sectionIds.add(c.getId());
182                         order.add(SECTION_TOKEN + c.getId());
183                     } else {
184                         collectIdsFromItems(((Container) c).getItems(), sectionIds, order, skipSections);
185                     }
186                 } else if (c instanceof InputField) {
187                     order.add(c.getId());
188                 }
189             }
190         }
191     }
192 
193     /**
194      * If true, the error messages will display the an InputField's title
195      * alongside the error, warning, and info messages related to it. This
196      * setting has no effect on messages which do not relate directly to a
197      * single InputField.
198      *
199      * @return the displayFieldLabelWithMessages
200      */
201     @BeanTagAttribute(name="displayFieldLabelWithMessages")
202     public boolean isDisplayFieldLabelWithMessages() {
203         return this.displayFieldLabelWithMessages;
204     }
205 
206     /**
207      * If true, the error messages will display the an InputField's title
208      * alongside the error, warning, and info messages related to it. This
209      * setting has no effect on messages which do not relate directly to a
210      * single InputField.
211      *
212      * @param displayFieldLabelWithMessages the displayFieldLabelWithMessages to set
213      */
214     public void setDisplayFieldLabelWithMessages(boolean displayFieldLabelWithMessages) {
215         this.displayFieldLabelWithMessages = displayFieldLabelWithMessages;
216     }
217 
218     /**
219      * When collapseAdditionalFieldLinkMessages is set to true, the messages generated on field links will be
220      * summarized to limit the space they take up with an appendage similar to [+n message type] appended for
221      * additional
222      * messages that are omitted.  When this flag is false, all messages will be part of the link separated by
223      * a comma.
224      *
225      * @return if field link messages are being collapsed
226      */
227     @BeanTagAttribute(name="collapseAdditionalFieldLinkMessages")
228     public boolean isCollapseAdditionalFieldLinkMessages() {
229         return collapseAdditionalFieldLinkMessages;
230     }
231 
232     /**
233      * Set collapseAdditionalFieldLinkMessages
234      *
235      * @param collapseAdditionalFieldLinkMessages - true if field link messages are being collapsed
236      */
237     public void setCollapseAdditionalFieldLinkMessages(boolean collapseAdditionalFieldLinkMessages) {
238         this.collapseAdditionalFieldLinkMessages = collapseAdditionalFieldLinkMessages;
239     }
240 }