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