View Javadoc

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