View Javadoc

1   /**
2    * Copyright 2005-2013 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.datadictionary.parse.BeanTags;
22  import org.kuali.rice.krad.datadictionary.validator.ValidationTrace;
23  import org.kuali.rice.krad.datadictionary.validator.Validator;
24  import org.kuali.rice.krad.uif.component.Component;
25  import org.kuali.rice.krad.uif.util.MessageStructureUtils;
26  import org.kuali.rice.krad.uif.view.View;
27  import org.kuali.rice.krad.util.KRADConstants;
28  
29  import java.util.List;
30  
31  /**
32   * Encapsulates a text message to be displayed
33   *
34   * <p>
35   * The <code>Message</code> is used to display static text in the user
36   * interface
37   * </p>
38   *
39   * @author Kuali Rice Team (rice.collab@kuali.org)
40   */
41  @BeanTags({@BeanTag(name = "message-bean", parent = "Uif-Message"),
42          @BeanTag(name = "instructionalMessage-bean", parent = "Uif-InstructionalMessage"),
43          @BeanTag(name = "constraintMessage-bean", parent = "Uif-ConstraintMessage"),
44          @BeanTag(name = "requiredMessage-bean", parent = "Uif-RequiredMessage"),
45          @BeanTag(name = "requiredInstructionsMessage-bean", parent = "Uif-RequiredInstructionsMessage"),
46          @BeanTag(name = "stateBased-requiredInstructionsMessage-bean",
47                  parent = "Uif-StateBased-RequiredInstructionsMessage"),
48          @BeanTag(name = "dialogPrompt-bean", parent = "Uif-DialogPrompt"),
49          @BeanTag(name = "imageCutineMessage-bean", parent = "Uif-ImageCutineMessage")})
50  public class Message extends ContentElementBase {
51      private static final long serialVersionUID = 4090058533452450395L;
52  
53      private String messageText;
54      private boolean generateSpan;
55  
56      private List<Component> inlineComponents;
57      private List<Component> messageComponentStructure;
58  
59      private boolean parseComponents;
60  
61      public Message() {
62          super();
63  
64          generateSpan = true;
65          parseComponents = true;
66      }
67  
68      /**
69       * Message perfom apply model parses message text for rich text functionality if the messageText contains
70       * [ or ] special characters
71       *
72       * @see Component#performApplyModel(org.kuali.rice.krad.uif.view.View, Object, org.kuali.rice.krad.uif.component.Component)
73       */
74      @Override
75      public void performApplyModel(View view, Object model, Component parent) {
76          super.performApplyModel(view, model, parent);
77  
78          //if messageText contains the special characters [] then parse and fill in the messageComponentStructure
79          //but if messageComponentStructure has already been set it overrides messageText by default
80          if (messageText != null && messageText.contains(KRADConstants.MessageParsing.LEFT_TOKEN) &&
81                  messageText.contains(KRADConstants.MessageParsing.RIGHT_TOKEN) &&
82                  (messageComponentStructure == null || messageComponentStructure.isEmpty())) {
83  
84              messageComponentStructure = MessageStructureUtils.parseMessage(this.getId(), this.getMessageText(),
85                      this.getInlineComponents(), view, parseComponents);
86  
87              if (messageComponentStructure != null) {
88                  for (Component component : messageComponentStructure) {
89                      view.getViewHelperService().performComponentInitialization(view, model, component);
90                  }
91              }
92          }
93  
94      }
95  
96      /**
97       * @see Component#performFinalize(org.kuali.rice.krad.uif.view.View, Object, org.kuali.rice.krad.uif.component.Component)
98       */
99      @Override
100     public void performFinalize(View view, Object model, Component parent) {
101         super.performFinalize(view, model, parent);
102         //Message needs to be aware of its own parent because it now contains content that can have validation
103         this.addDataAttribute("parent", parent.getId());
104     }
105 
106     /**
107      * @see org.kuali.rice.krad.uif.component.ComponentBase#getComponentsForLifecycle()
108      */
109     @Override
110     public List<Component> getComponentsForLifecycle() {
111         List<Component> components = super.getComponentsForLifecycle();
112 
113         if (messageComponentStructure != null) {
114             for (Component component : messageComponentStructure) {
115                 components.add(component);
116             }
117         }
118 
119         return components;
120     }
121 
122     /**
123      * Override to render only if the message text has been given or there is a conditional expression on the
124      * message text
125      *
126      * @see org.kuali.rice.krad.uif.component.ComponentBase#isRender()
127      */
128     @Override
129     public boolean isRender() {
130         boolean render = super.isRender();
131 
132         if (render) {
133             render = getPropertyExpressions().containsKey("messageText") || (StringUtils.isNotBlank(messageText)
134                     && !StringUtils.equals(messageText, "&nbsp;"));
135         }
136 
137         return render;
138     }
139 
140     /**
141      * Text that makes up the message that will be displayed.
142      *
143      * <p>If special characters [] are detected the message inserts special content at that location.
144      * The types of features supported are (note that &lt;&gt; are not part of the content below,
145      * they specify placeholders):
146      * <ul>
147      * <li>[id=&lt;component id&gt;] - insert component with id specified at that location in the message</li>
148      * <li>[n] - insert component at index n from the inlineComponent list</li>
149      * <li>[&lt;html tag&gt;][/&lt;html tag&gt;] - insert html content directly into the message content at that
150      * location,
151      * without the need to escape the &lt;&gt; characters in xml</li>
152      * <li>[color=&lt;html color code/name&gt;][/color] - wrap content in color tags to make text that color
153      * in the message</li>
154      * <li>[css=&lt;css classes&gt;][/css] - apply css classes specified to the wrapped content - same as wrapping
155      * the content in span with class property set</li>
156      * </ul>
157      * If the [] characters are needed in message text, they need to be declared with an escape character: \\[ \\]
158      * </p>
159      *
160      * @return String message text
161      */
162     @BeanTagAttribute(name = "messageText")
163     public String getMessageText() {
164         return this.messageText;
165     }
166 
167     /**
168      * Setter for the message text
169      *
170      * @param messageText
171      */
172     public void setMessageText(String messageText) {
173         this.messageText = messageText;
174     }
175 
176     /**
177      * If true, generate the span around this message (default).  When false, skip span generation for this
178      * message - this has the additional effect the css classes/style classes will be lost for this message.
179      *
180      * @return true if generating a wrapping span, false otherwise
181      */
182     @BeanTagAttribute(name = "generateSpan")
183     public boolean isGenerateSpan() {
184         return generateSpan;
185     }
186 
187     /**
188      * Sets the generate span flag
189      *
190      * @param generateSpan
191      */
192     public void setGenerateSpan(boolean generateSpan) {
193         this.generateSpan = generateSpan;
194     }
195 
196     /**
197      * The message component structure is a list of components which represent the components that make up a message
198      * when using rich message functionality.
199      *
200      * <p>The structure represents the parsed messageText when not set. Normally this structure is setup by the Message
201      * class and <b>SHOULD NOT BE SET</b> in xml, unless full control over the structure is needed.  </p>
202      *
203      * @return list of components which represent the message structure
204      */
205     public List<Component> getMessageComponentStructure() {
206         return messageComponentStructure;
207     }
208 
209     /**
210      * Set the message component structure.  This will override/ignore messageText when set. Normally
211      * this <b>SHOULD NOT BE SET</b> by the xml configuration.
212      *
213      * @param messageComponentStructure list of components which represent the message structure
214      */
215     public void setMessageComponentStructure(List<Component> messageComponentStructure) {
216         this.messageComponentStructure = messageComponentStructure;
217     }
218 
219     /**
220      * The inlineComponents are a list of components in order by index.
221      *
222      * <p>inlineComponents is only used when the message is using rich message functionality.  A message
223      * with [0] will reference component at index 0 of this list and insert it at that place in the message,
224      * and likewise [1] will reference item 1, etc.  If the index referenced is out of bounds (or list doesnt exist),
225      * an error will be thrown during message parse.</p>
226      *
227      * @return the inlineComponents to be filled in at indexes referenced by [n] in the message
228      */
229     @BeanTagAttribute(name = "inlineComponents", type = BeanTagAttribute.AttributeType.LISTBEAN)
230     public List<Component> getInlineComponents() {
231         return inlineComponents;
232     }
233 
234     /**
235      * Set the inlineComponents to be filled in at indexes referenced by [n] in the message
236      *
237      * @param inlineComponents the inlineComponents to be filled in at indexes referenced by [n] in the message
238      */
239     public void setInlineComponents(List<Component> inlineComponents) {
240         this.inlineComponents = inlineComponents;
241     }
242 
243     /**
244      * @see org.kuali.rice.krad.uif.component.Component#completeValidation
245      */
246     @Override
247     public void completeValidation(ValidationTrace tracer) {
248         tracer.addBean(this);
249 
250         // Checks that text is set
251         if (getMessageText() == null) {
252             if (Validator.checkExpressions(this, "messageText")) {
253                 String currentValues[] = {"messageText  =" + getMessageText()};
254                 tracer.createWarning("MessageText should be set", currentValues);
255             }
256         }
257 
258         super.completeValidation(tracer.getCopy());
259     }
260 
261     /**
262      * Indicates if the inline components must be parsed for rich messages
263      *
264      * @return boolean
265      */
266     @BeanTagAttribute(name = "parseComponents")
267     public boolean isParseComponents() {
268         return parseComponents;
269     }
270 
271     /**
272      * Sets the parse components flag to indicate if inline components must be parsed for rich messages
273      *
274      * @param parseComponents
275      */
276     public void setParseComponents(boolean parseComponents) {
277         this.parseComponents = parseComponents;
278     }
279 }