You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mm...@apache.org on 2007/08/29 16:51:49 UTC
svn commit: r570827 -
/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java
Author: mmarinschek
Date: Wed Aug 29 07:51:48 2007
New Revision: 570827
URL: http://svn.apache.org/viewvc?rev=570827&view=rev
Log:
NPE if label null
Modified:
myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java
Modified: myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java
URL: http://svn.apache.org/viewvc/myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java?rev=570827&r1=570826&r2=570827&view=diff
==============================================================================
--- myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java (original)
+++ myfaces/trinidad/trunk/trinidad/trinidad-impl/src/main/java/org/apache/myfaces/trinidadinternal/renderkit/core/xhtml/MessageBoxRenderer.java Wed Aug 29 07:51:48 2007
@@ -1,548 +1,539 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.myfaces.trinidadinternal.renderkit.core.xhtml;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import javax.faces.application.FacesMessage;
-import javax.faces.component.UIComponent;
-import javax.faces.context.FacesContext;
-import javax.faces.context.ResponseWriter;
-
-import org.apache.myfaces.trinidad.bean.FacesBean;
-import org.apache.myfaces.trinidad.bean.PropertyKey;
-import org.apache.myfaces.trinidad.component.core.output.CoreMessages;
-
-import org.apache.myfaces.trinidad.context.RenderingContext;
-import org.apache.myfaces.trinidad.context.RequestContext;
-import org.apache.myfaces.trinidad.skin.Icon;
-import org.apache.myfaces.trinidad.util.LabeledFacesMessage;
-import org.apache.myfaces.trinidadinternal.util.MessageUtils;
-
-/**
- * Renderer for org.apache.myfaces.trinidad.Messages, family org.apache.myfaces.trinidad.Messages.
- *
- */
-public class MessageBoxRenderer extends XhtmlRenderer
-{
- public MessageBoxRenderer()
- {
- this(CoreMessages.TYPE);
- }
-
- protected MessageBoxRenderer(FacesBean.Type type)
- {
- super(type);
- }
-
- @Override
- protected void findTypeConstants(FacesBean.Type type)
- {
- super.findTypeConstants(type);
- _textKey = type.findKey("text");
- _messageKey = type.findKey("message");
- _globalOnlyKey = type.findKey("globalOnly");
-
- _headerRenderer = new HeaderRenderer(type);
- _boxRenderer = new BoxRenderer(type);
- }
-
- @Override
- public boolean getRendersChildren()
- {
- return true;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- protected void encodeAll(FacesContext context, RenderingContext arc,
- UIComponent component, FacesBean bean) throws IOException
- {
- // Force MessageBox to be re-rendered via PPR, since the set
- // of messages may have changed.
- RequestContext afContext = RequestContext.getCurrentInstance();
- if (afContext != null)
- afContext.addPartialTarget(component);
-
- ResponseWriter writer = context.getResponseWriter();
-
- Map<String, String> origSkinResourceMap = arc.getSkinResourceKeyMap();
-
- // Setup the rendering context, so that default skin selectors of
- // delegate renderers are mapped to those of this renderer
- arc.setSkinResourceKeyMap(_RESOURCE_KEY_MAP);
-
- // Check if INLINE validation mode is enabled
- boolean inlineValidation =
- RequestContext.ClientValidation.INLINE.equals(
- RequestContext.getCurrentInstance().getClientValidation());
-
- // Only when there's at least one message queued
- if (inlineValidation || context.getMessages().hasNext())
- {
-
- if (inlineValidation)
- {
- writer.startElement(XhtmlConstants.SCRIPT_ELEMENT, null);
- renderScriptDeferAttribute(context, arc);
- renderScriptTypeAttribute(context, arc);
-
- // Output the styles required for client-side manipulation of the MessageBox
-
- // Output style for list of messages
- writer.writeText("TrPage.getInstance().addStyleClassMap( {'", null);
- writer.writeText(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS + "':'", null);
- writer.writeText(arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS), null);
-
- // Single entry list uses two styles
- writer.writeText("','" + SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS + "':'", null);
- writer.writeText(arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS), null);
- writer.writeText(" " + arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS), null);
-
- // Output Style for MessageBox Anchors
- writer.writeText("','" + SkinSelectors.LINK_STYLE_CLASS + "':'", null);
- writer.writeText(arc.getStyleClass(SkinSelectors.LINK_STYLE_CLASS), null);
- writer.writeText("'} ); ", null);
-
- // Output the script that will register the MessageBox with
- // the TrMessageBox javascript class that handles client-side
- // add/remove of messages.
- writer.writeText("TrMessageBox._registerMessageBox(\"", null);
- writer.writeText(getClientId(context, component), null);
- writer.writeText("\");", null);
- writer.endElement("script");
- }
-
- // Delegate rendering of the outer shell to the BoxRenderer class
- // which will call back to this renderer to output the messages
- _boxRenderer.encodeAll(context, arc, component, bean);
- }
- else
- {
- // Always render an element, for update at PPR-time
- writer.startElement(XhtmlConstants.SPAN_ELEMENT, component);
- renderId(context, component);
- writer.endElement(XhtmlConstants.SPAN_ELEMENT);
- }
-
- // Reset the skin resource map
- arc.setSkinResourceKeyMap(origSkinResourceMap);
- }
-
- protected void _renderContent(
- FacesContext context,
- RenderingContext arc,
- UIComponent component,
- FacesBean bean)
- throws IOException
- {
- ResponseWriter writer = context.getResponseWriter();
-
- boolean globalOnly = isGlobalOnly(bean);
-
- // TODO - Merge styles into AF_MESSAGES_STYLE_CLASS
- writer.startElement(XhtmlConstants.DIV_ELEMENT, component);
- renderStyleClass(context, arc, SkinSelectors.AF_MESSAGES_BODY_STYLE_CLASS);
-
- _renderHeader(context, arc, component, bean);
-
- // Render the 'message' attribute if specified
- String message = getMessage(bean);
- if (message != null)
- {
- writer.startElement(XhtmlConstants.DIV_ELEMENT, null);
- renderStyleClass(context, arc, SkinSelectors.AF_MESSAGES_MESSAGE_TEXT_STYLE_CLASS);
- writer.write(message);
- writer.endElement(XhtmlConstants.DIV_ELEMENT);
- }
-
- // Render messages as a list
- writer.startElement("ol", null);
-
- // Output an id for the list so client-side validation can
- // easily access the element
- String listId = getClientId(context, component) + "__LIST__";
- writer.writeAttribute(XhtmlConstants.ID_ATTRIBUTE, listId, null);
-
- // Switch list style depending if no. of messages is 1 or >1
- String[] styleClasses = null;
- if (MessageUtils.multipleMessagesQueued(context, globalOnly))
- styleClasses = new String[] {SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS};
- else
- styleClasses = new String[] {SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS};
-
- renderStyleClasses(context, arc, styleClasses);
-
- _renderGlobalMessages(context, arc, component, bean);
-
- if (!globalOnly)
- _renderComponentMessages(context, arc, component, bean);
-
- // End of list
- writer.endElement("ol");
-
- writer.endElement(XhtmlConstants.DIV_ELEMENT);
- }
-
- @SuppressWarnings("unchecked")
- protected void _renderGlobalMessages(
- FacesContext context,
- RenderingContext arc,
- UIComponent component,
- FacesBean bean)
- throws IOException
- {
- ResponseWriter writer = context.getResponseWriter();
-
- // Get all messages without and id
- Iterator<FacesMessage> msgIter = context.getMessages(null);
- while (msgIter.hasNext())
- {
- FacesMessage msg = msgIter.next();
-
- writer.startElement("li", null);
-
- String text = MessageUtils.getGlobalMessage(arc, msg.getSummary(), msg.getDetail());
- renderPossiblyFormattedText(context, text);
-
- writer.endElement("li");
- }
- }
-
- @SuppressWarnings("unchecked")
- protected void _renderComponentMessages(
- FacesContext context,
- RenderingContext arc,
- UIComponent component,
- FacesBean bean)
- throws IOException
- {
- ResponseWriter writer = context.getResponseWriter();
-
- Iterator<String> idIter = context.getClientIdsWithMessages();
- while (idIter.hasNext())
- {
- String id = idIter.next();
-
- // Skip global messages
- if (id == null)
- continue;
-
- Iterator<FacesMessage> msgIter = context.getMessages(id);
- while (msgIter.hasNext())
- {
- FacesMessage msg = msgIter.next();
-
- writer.startElement("li", null);
-
- _renderMessageAnchor(context, arc, msg, id);
-
- String text = MessageUtils.getClientMessage(arc, msg.getSummary(), msg.getDetail());
-
- renderPossiblyFormattedText(context, text);
-
- writer.endElement("li");
- }
- }
- }
-
- protected void _renderHeader(
- FacesContext context,
- RenderingContext arc,
- UIComponent component,
- FacesBean bean) throws IOException
- {
- delegateRenderer(context, arc, component, bean, _headerRenderer);
- }
-
- protected void _renderMessageAnchor(
- FacesContext context,
- RenderingContext arc,
- FacesMessage msg,
- String componentId) throws IOException
- {
- ResponseWriter writer = context.getResponseWriter();
-
- if (componentId == null)
- return;
-
- // Anchor rendering currently only possible for messages that
- // contain a label, but we could use summary text in future
- if (msg instanceof LabeledFacesMessage)
- {
- LabeledFacesMessage labeledMsg = (LabeledFacesMessage)msg;
- String anchor = MessageUtils.getAnchor(componentId);
- if (anchor != null)
- {
- writer.startElement(XhtmlConstants.LINK_ELEMENT, null);
- renderStyleClass(context, arc, SkinSelectors.LINK_STYLE_CLASS);
- writer.writeAttribute(XhtmlConstants.HREF_ATTRIBUTE, "#" + anchor, null);
- writer.write(labeledMsg.getLabel().toString());
- writer.endElement(XhtmlConstants.LINK_ELEMENT);
- }
- }
- }
-
- // Rendering delegate to handle output of the header for the message box
- private class HeaderRenderer extends PanelHeaderRenderer
- {
- public HeaderRenderer(FacesBean.Type type)
- {
- super(type);
- }
-
- @Override
- protected boolean shouldRenderId(FacesContext context, UIComponent component)
- {
- // Header will always be refreshed as sub-element of parent
- return false;
- }
-
- @Override
- protected void renderEventHandlers(FacesContext context, FacesBean bean)
- throws IOException
- {
- // Prevent HeaderRenderer from re-rendering event handlers
- }
-
- @Override
- protected String getMessageType(FacesBean bean)
- {
- String messageType = null;
-
- FacesMessage.Severity maxSeverity =
- FacesContext.getCurrentInstance().getMaximumSeverity();
-
- // Map FacesMessage severity to levels expected by panelHeaderRenderer
- if (maxSeverity == null)
- messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
- else if (FacesMessage.SEVERITY_FATAL.equals(maxSeverity))
- messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
- else if (FacesMessage.SEVERITY_ERROR.equals(maxSeverity))
- messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
- else if (FacesMessage.SEVERITY_WARN.equals(maxSeverity))
- messageType = XhtmlConstants.MESSAGE_TYPE_WARNING;
- else if (FacesMessage.SEVERITY_INFO.equals(maxSeverity))
- messageType = XhtmlConstants.MESSAGE_TYPE_INFO;
-
- return messageType;
- }
-
- @Override
- protected String getText(RenderingContext arc, FacesBean bean,
- String messageType)
- {
- String text = MessageBoxRenderer.this.getText(bean);
- if (text != null)
- // Use Text attribute of this component for header text
- return text;
-
- // Otherwise parent will decide text & style based on messageType
- return super.getText(arc, bean, messageType);
- }
-
- @Override
- protected String getMessageIconName(String messageType)
- {
- String iconName = null;
-
- // Use the af|messages skin selectors instead of those
- // used by panelHeader
- if (XhtmlConstants.MESSAGE_TYPE_ERROR.equals(messageType))
- iconName = SkinSelectors.AF_MESSAGES_ERROR_ICON_NAME;
- else if (XhtmlConstants.MESSAGE_TYPE_WARNING.equals(messageType))
- iconName = SkinSelectors.AF_MESSAGES_WARNING_ICON_NAME;
- else if (XhtmlConstants.MESSAGE_TYPE_INFO.equals(messageType))
- iconName = SkinSelectors.AF_MESSAGES_INFO_ICON_NAME;
- else if (XhtmlConstants.MESSAGE_TYPE_CONFIRMATION.equals(messageType))
- iconName = SkinSelectors.AF_MESSAGES_CONFIRMATION_ICON_NAME;
-
- assert ((iconName != null) ||
- XhtmlConstants.MESSAGE_TYPE_NONE.equals(messageType));
-
- return iconName;
- }
-
- }
-
- // Delegate renderer, handles the outer element rendering and
- // provides option to wrap message box using rounded borders etc.
- private class BoxRenderer extends PanelBoxRenderer
- {
-
- public BoxRenderer(FacesBean.Type type)
- {
- super(type);
- }
-
- @Override
- protected boolean shouldRenderId(FacesContext context, UIComponent component)
- {
- // As panelBox is handling the outer rendering, then it should render
- // the id of the MessageBox component
- return true;
- }
-
- @Override
- protected String getBackground(FacesBean bean)
- {
- // Force use of 'light' style, so we know which style
- // to re-map in _RESOURCE_KEY_MAP
- return "light";
- }
-
- @Override
- protected String getInlineStyle(FacesBean bean)
- {
- String inlineStyle = super.getInlineStyle(bean);
-
- boolean inlineValidation =
- RequestContext.ClientValidation.INLINE.equals(
- RequestContext.getCurrentInstance().getClientValidation());
-
- if (!inlineValidation)
- return inlineStyle;
-
- boolean hasMessages = FacesContext.getCurrentInstance().getMessages().hasNext();
-
- if (hasMessages)
- return inlineStyle;
-
- // Ensure the MessageBox is hidden for inline mode when
- // there are no messages
- if (inlineStyle == null)
- return "display:none";
- else
- return inlineStyle + ";display:none";
- }
-
- @Override
- protected boolean hasChildren(UIComponent component)
- {
- // Required to force panelBox to call render properly
- return true;
- }
-
- @Override
- protected void renderBody(FacesContext context, RenderingContext arc,
- UIComponent component, FacesBean bean, Object icon, Object text) throws IOException
- {
- // Pass control back to MessageBoxRenderer to continue rendering
- // the content of the message box.
- MessageBoxRenderer.this._renderContent(context, arc, component, bean);
- }
- }
-
- @Override
- protected boolean shouldRenderId(FacesContext context, UIComponent component)
- {
- // Normally BoxRenderer will output the id for this component, but
- // if we're just outputting an empty element for PPR purposes, then
- // this renderer should output the id.
- return true;
- }
-
- protected String getText(FacesBean bean)
- {
- if (_textKey == null)
- return null;
- return toString(bean.getProperty(_textKey));
- }
-
- protected String getMessage(FacesBean bean)
- {
- if (_messageKey == null)
- return null;
- return toString(bean.getProperty(_messageKey));
- }
-
- protected boolean isGlobalOnly(FacesBean bean)
- {
- Object o = bean.getProperty(_globalOnlyKey);
- if (o == null)
- o = _globalOnlyKey.getDefault();
- return Boolean.TRUE.equals(o);
- }
-
- private PropertyKey _textKey;
- private PropertyKey _messageKey;
- private PropertyKey _globalOnlyKey;
- private XhtmlRenderer _headerRenderer;
- private PanelBoxRenderer _boxRenderer;
-
- // Map panelHeader & panelBox Styles/Icons etc. to this renderer's selectors.
- private static final Map<String, String> _RESOURCE_KEY_MAP;
-
- static
- {
- _RESOURCE_KEY_MAP = new HashMap<String, String>();
-
- // translation keys
- _RESOURCE_KEY_MAP.put("af_panelHeader.INFORMATION",
- "af_messages.INFORMATION");
- _RESOURCE_KEY_MAP.put("af_panelHeader.WARNING",
- "af_messages.WARNING");
- _RESOURCE_KEY_MAP.put("af_panelHeader.ERROR",
- "af_messages.ERROR");
- _RESOURCE_KEY_MAP.put("af_panelHeader.CONFIRMATION",
- "af_messages.CONFIRMATION");
- // icons
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_ERROR_ICON_NAME,
- SkinSelectors.AF_MESSAGES_ERROR_ICON_NAME);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_WARNING_ICON_NAME,
- SkinSelectors.AF_MESSAGES_WARNING_ICON_NAME);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_INFO_ICON_NAME,
- SkinSelectors.AF_MESSAGES_INFO_ICON_NAME);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_CONFIRMATION_ICON_NAME,
- SkinSelectors.AF_MESSAGES_CONFIRMATION_ICON_NAME);
-
- // styles
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_ERROR_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_ERROR_STYLE_CLASS);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_HEADER_STYLE_CLASS);
-
- // We forced the use of 'light' style above, so now map it
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_LIGHT_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_STYLE_CLASS);
-
- // frame styles
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_START_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_TOP_START_STYLE_CLASS);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_TOP_STYLE_CLASS);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_END_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_TOP_END_STYLE_CLASS);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_START_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_START_STYLE_CLASS);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_END_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_END_STYLE_CLASS);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_START_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_BOTTOM_START_STYLE_CLASS);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_BOTTOM_STYLE_CLASS);
- _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_END_STYLE_CLASS,
- SkinSelectors.AF_MESSAGES_BOTTOM_END_STYLE_CLASS);
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.trinidadinternal.renderkit.core.xhtml;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import org.apache.myfaces.trinidad.bean.FacesBean;
+import org.apache.myfaces.trinidad.bean.PropertyKey;
+import org.apache.myfaces.trinidad.component.core.output.CoreMessages;
+
+import org.apache.myfaces.trinidad.context.RenderingContext;
+import org.apache.myfaces.trinidad.context.RequestContext;
+import org.apache.myfaces.trinidad.skin.Icon;
+import org.apache.myfaces.trinidad.util.LabeledFacesMessage;
+import org.apache.myfaces.trinidadinternal.util.MessageUtils;
+
+/**
+ * Renderer for org.apache.myfaces.trinidad.Messages, family org.apache.myfaces.trinidad.Messages.
+ *
+ */
+public class MessageBoxRenderer extends XhtmlRenderer
+{
+ public MessageBoxRenderer()
+ {
+ this(CoreMessages.TYPE);
+ }
+
+ protected MessageBoxRenderer(FacesBean.Type type)
+ {
+ super(type);
+ }
+
+ @Override
+ protected void findTypeConstants(FacesBean.Type type)
+ {
+ super.findTypeConstants(type);
+ _textKey = type.findKey("text");
+ _messageKey = type.findKey("message");
+ _globalOnlyKey = type.findKey("globalOnly");
+
+ _headerRenderer = new HeaderRenderer(type);
+ _boxRenderer = new BoxRenderer(type);
+ }
+
+ @Override
+ public boolean getRendersChildren()
+ {
+ return true;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void encodeAll(FacesContext context, RenderingContext arc,
+ UIComponent component, FacesBean bean) throws IOException
+ {
+ // Force MessageBox to be re-rendered via PPR, since the set
+ // of messages may have changed.
+ RequestContext afContext = RequestContext.getCurrentInstance();
+ if (afContext != null)
+ afContext.addPartialTarget(component);
+
+ ResponseWriter writer = context.getResponseWriter();
+
+ // Check if INLINE validation mode is enabled
+ boolean inlineValidation =
+ RequestContext.ClientValidation.INLINE.equals(
+ RequestContext.getCurrentInstance().getClientValidation());
+
+ // Only when there's at least one message queued
+ if (inlineValidation || context.getMessages().hasNext())
+ {
+
+ if (inlineValidation)
+ {
+ writer.startElement(XhtmlConstants.SCRIPT_ELEMENT, null);
+ renderScriptDeferAttribute(context, arc);
+ renderScriptTypeAttribute(context, arc);
+
+ // Output the styles required for client-side manipulation of the MessageBox
+
+ // Output style for list of messages
+ writer.writeText("TrPage.getInstance().addStyleClassMap( {'", null);
+ writer.writeText(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS + "':'", null);
+ writer.writeText(arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS), null);
+
+ // Single entry list uses two styles
+ writer.writeText("','" + SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS + "':'", null);
+ writer.writeText(arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS), null);
+ writer.writeText(" " + arc.getStyleClass(SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS), null);
+
+ // Output Style for MessageBox Anchors
+ writer.writeText("','" + SkinSelectors.LINK_STYLE_CLASS + "':'", null);
+ writer.writeText(arc.getStyleClass(SkinSelectors.LINK_STYLE_CLASS), null);
+ writer.writeText("'} ); ", null);
+
+ // Output the script that will register the MessageBox with
+ // the TrMessageBox javascript class that handles client-side
+ // add/remove of messages.
+ writer.writeText("TrMessageBox._registerMessageBox(\"", null);
+ writer.writeText(getClientId(context, component), null);
+ writer.writeText("\");", null);
+ writer.endElement("script");
+ }
+
+ // Setup the rendering context, so that default skin selectors of
+ // delegate renderers are mapped to those of this renderer
+ arc.setSkinResourceKeyMap(_RESOURCE_KEY_MAP);
+
+ // Delegate rendering of the outer shell to the BoxRenderer class
+ // which will call back to this renderer to output the messages
+ _boxRenderer.encodeAll(context, arc, component, bean);
+ }
+ else
+ {
+ // Always render an element, for update at PPR-time
+ writer.startElement(XhtmlConstants.SPAN_ELEMENT, component);
+ renderId(context, component);
+ writer.endElement(XhtmlConstants.SPAN_ELEMENT);
+ }
+ }
+
+ protected void _renderContent(
+ FacesContext context,
+ RenderingContext arc,
+ UIComponent component,
+ FacesBean bean)
+ throws IOException
+ {
+ ResponseWriter writer = context.getResponseWriter();
+
+ boolean globalOnly = isGlobalOnly(bean);
+
+ // TODO - Merge styles into AF_MESSAGES_STYLE_CLASS
+ writer.startElement(XhtmlConstants.DIV_ELEMENT, component);
+ renderStyleClass(context, arc, SkinSelectors.AF_MESSAGES_BODY_STYLE_CLASS);
+
+ _renderHeader(context, arc, component, bean);
+
+ // Render the 'message' attribute if specified
+ String message = getMessage(bean);
+ if (message != null)
+ {
+ writer.startElement(XhtmlConstants.DIV_ELEMENT, null);
+ renderStyleClass(context, arc, SkinSelectors.AF_MESSAGES_MESSAGE_TEXT_STYLE_CLASS);
+ writer.write(message);
+ writer.endElement(XhtmlConstants.DIV_ELEMENT);
+ }
+
+ // Render messages as a list
+ writer.startElement("ol", null);
+
+ // Output an id for the list so client-side validation can
+ // easily access the element
+ String listId = getClientId(context, component) + "__LIST__";
+ writer.writeAttribute(XhtmlConstants.ID_ATTRIBUTE, listId, null);
+
+ // Switch list style depending if no. of messages is 1 or >1
+ String[] styleClasses = null;
+ if (MessageUtils.multipleMessagesQueued(context, globalOnly))
+ styleClasses = new String[] {SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS};
+ else
+ styleClasses = new String[] {SkinSelectors.AF_MESSAGES_LIST_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_LIST_SINGLE_STYLE_CLASS};
+
+ renderStyleClasses(context, arc, styleClasses);
+
+ _renderGlobalMessages(context, arc, component, bean);
+
+ if (!globalOnly)
+ _renderComponentMessages(context, arc, component, bean);
+
+ // End of list
+ writer.endElement("ol");
+
+ writer.endElement(XhtmlConstants.DIV_ELEMENT);
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void _renderGlobalMessages(
+ FacesContext context,
+ RenderingContext arc,
+ UIComponent component,
+ FacesBean bean)
+ throws IOException
+ {
+ ResponseWriter writer = context.getResponseWriter();
+
+ // Get all messages without and id
+ Iterator<FacesMessage> msgIter = context.getMessages(null);
+ while (msgIter.hasNext())
+ {
+ FacesMessage msg = msgIter.next();
+
+ writer.startElement("li", null);
+
+ String text = MessageUtils.getGlobalMessage(arc, msg.getSummary(), msg.getDetail());
+ renderPossiblyFormattedText(context, text);
+
+ writer.endElement("li");
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected void _renderComponentMessages(
+ FacesContext context,
+ RenderingContext arc,
+ UIComponent component,
+ FacesBean bean)
+ throws IOException
+ {
+ ResponseWriter writer = context.getResponseWriter();
+
+ Iterator<String> idIter = context.getClientIdsWithMessages();
+ while (idIter.hasNext())
+ {
+ String id = idIter.next();
+
+ // Skip global messages
+ if (id == null)
+ continue;
+
+ Iterator<FacesMessage> msgIter = context.getMessages(id);
+ while (msgIter.hasNext())
+ {
+ FacesMessage msg = msgIter.next();
+
+ writer.startElement("li", null);
+
+ _renderMessageAnchor(context, arc, msg, id);
+
+ String text = MessageUtils.getClientMessage(arc, msg.getSummary(), msg.getDetail());
+
+ renderPossiblyFormattedText(context, text);
+
+ writer.endElement("li");
+ }
+ }
+ }
+
+ protected void _renderHeader(
+ FacesContext context,
+ RenderingContext arc,
+ UIComponent component,
+ FacesBean bean) throws IOException
+ {
+ delegateRenderer(context, arc, component, bean, _headerRenderer);
+ }
+
+ protected void _renderMessageAnchor(
+ FacesContext context,
+ RenderingContext arc,
+ FacesMessage msg,
+ String componentId) throws IOException
+ {
+ ResponseWriter writer = context.getResponseWriter();
+
+ if (componentId == null)
+ return;
+
+ // Anchor rendering currently only possible for messages that
+ // contain a label, but we could use summary text in future
+ if (msg instanceof LabeledFacesMessage)
+ {
+ LabeledFacesMessage labeledMsg = (LabeledFacesMessage)msg;
+ String anchor = MessageUtils.getAnchor(componentId);
+ if (anchor != null)
+ {
+ writer.startElement(XhtmlConstants.LINK_ELEMENT, null);
+ renderStyleClass(context, arc, SkinSelectors.LINK_STYLE_CLASS);
+ writer.writeAttribute(XhtmlConstants.HREF_ATTRIBUTE, "#" + anchor, null);
+ writer.write(labeledMsg.getLabel().toString());
+ writer.endElement(XhtmlConstants.LINK_ELEMENT);
+ }
+ }
+ }
+
+ // Rendering delegate to handle output of the header for the message box
+ private class HeaderRenderer extends PanelHeaderRenderer
+ {
+ public HeaderRenderer(FacesBean.Type type)
+ {
+ super(type);
+ }
+
+ @Override
+ protected boolean shouldRenderId(FacesContext context, UIComponent component)
+ {
+ // Header will always be refreshed as sub-element of parent
+ return false;
+ }
+
+ @Override
+ protected void renderEventHandlers(FacesContext context, FacesBean bean)
+ throws IOException
+ {
+ // Prevent HeaderRenderer from re-rendering event handlers
+ }
+
+ @Override
+ protected String getMessageType(FacesBean bean)
+ {
+ String messageType = null;
+
+ FacesMessage.Severity maxSeverity =
+ FacesContext.getCurrentInstance().getMaximumSeverity();
+
+ // Map FacesMessage severity to levels expected by panelHeaderRenderer
+ if (maxSeverity == null)
+ messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
+ else if (FacesMessage.SEVERITY_FATAL.equals(maxSeverity))
+ messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
+ else if (FacesMessage.SEVERITY_ERROR.equals(maxSeverity))
+ messageType = XhtmlConstants.MESSAGE_TYPE_ERROR;
+ else if (FacesMessage.SEVERITY_WARN.equals(maxSeverity))
+ messageType = XhtmlConstants.MESSAGE_TYPE_WARNING;
+ else if (FacesMessage.SEVERITY_INFO.equals(maxSeverity))
+ messageType = XhtmlConstants.MESSAGE_TYPE_INFO;
+
+ return messageType;
+ }
+
+ @Override
+ protected String getText(RenderingContext arc, FacesBean bean,
+ String messageType)
+ {
+ String text = MessageBoxRenderer.this.getText(bean);
+ if (text != null)
+ // Use Text attribute of this component for header text
+ return text;
+
+ // Otherwise parent will decide text & style based on messageType
+ return super.getText(arc, bean, messageType);
+ }
+
+ @Override
+ protected String getMessageIconName(String messageType)
+ {
+ String iconName = null;
+
+ // Use the af|messages skin selectors instead of those
+ // used by panelHeader
+ if (XhtmlConstants.MESSAGE_TYPE_ERROR.equals(messageType))
+ iconName = SkinSelectors.AF_MESSAGES_ERROR_ICON_NAME;
+ else if (XhtmlConstants.MESSAGE_TYPE_WARNING.equals(messageType))
+ iconName = SkinSelectors.AF_MESSAGES_WARNING_ICON_NAME;
+ else if (XhtmlConstants.MESSAGE_TYPE_INFO.equals(messageType))
+ iconName = SkinSelectors.AF_MESSAGES_INFO_ICON_NAME;
+ else if (XhtmlConstants.MESSAGE_TYPE_CONFIRMATION.equals(messageType))
+ iconName = SkinSelectors.AF_MESSAGES_CONFIRMATION_ICON_NAME;
+
+ assert ((iconName != null) ||
+ XhtmlConstants.MESSAGE_TYPE_NONE.equals(messageType));
+
+ return iconName;
+ }
+
+ }
+
+ // Delegate renderer, handles the outer element rendering and
+ // provides option to wrap message box using rounded borders etc.
+ private class BoxRenderer extends PanelBoxRenderer
+ {
+
+ public BoxRenderer(FacesBean.Type type)
+ {
+ super(type);
+ }
+
+ @Override
+ protected boolean shouldRenderId(FacesContext context, UIComponent component)
+ {
+ // As panelBox is handling the outer rendering, then it should render
+ // the id of the MessageBox component
+ return true;
+ }
+
+ @Override
+ protected String getBackground(FacesBean bean)
+ {
+ // Force use of 'light' style, so we know which style
+ // to re-map in _RESOURCE_KEY_MAP
+ return "light";
+ }
+
+ @Override
+ protected String getInlineStyle(FacesBean bean)
+ {
+ String inlineStyle = super.getInlineStyle(bean);
+
+ boolean inlineValidation =
+ RequestContext.ClientValidation.INLINE.equals(
+ RequestContext.getCurrentInstance().getClientValidation());
+
+ if (!inlineValidation)
+ return inlineStyle;
+
+ boolean hasMessages = FacesContext.getCurrentInstance().getMessages().hasNext();
+
+ if (hasMessages)
+ return inlineStyle;
+
+ // Ensure the MessageBox is hidden for inline mode when there are no messages
+ return inlineStyle + ";display:none;";
+ }
+
+ @Override
+ protected boolean hasChildren(UIComponent component)
+ {
+ // Required to force panelBox to call render properly
+ return true;
+ }
+
+ @Override
+ protected void renderBody(FacesContext context, RenderingContext arc,
+ UIComponent component, FacesBean bean, Object icon, Object text) throws IOException
+ {
+ // Pass control back to MessageBoxRenderer to continue rendering
+ // the content of the message box.
+ MessageBoxRenderer.this._renderContent(context, arc, component, bean);
+ }
+ }
+
+ @Override
+ protected boolean shouldRenderId(FacesContext context, UIComponent component)
+ {
+ // Normally BoxRenderer will output the id for this component, but
+ // if we're just outputting an empty element for PPR purposes, then
+ // this renderer should output the id.
+ return true;
+ }
+
+ protected String getText(FacesBean bean)
+ {
+ if (_textKey == null)
+ return null;
+ return toString(bean.getProperty(_textKey));
+ }
+
+ protected String getMessage(FacesBean bean)
+ {
+ if (_messageKey == null)
+ return null;
+ return toString(bean.getProperty(_messageKey));
+ }
+
+ protected boolean isGlobalOnly(FacesBean bean)
+ {
+ Object o = bean.getProperty(_globalOnlyKey);
+ if (o == null)
+ o = _globalOnlyKey.getDefault();
+ return Boolean.TRUE.equals(o);
+ }
+
+ private PropertyKey _textKey;
+ private PropertyKey _messageKey;
+ private PropertyKey _globalOnlyKey;
+ private XhtmlRenderer _headerRenderer;
+ private PanelBoxRenderer _boxRenderer;
+
+ // Map panelHeader & panelBox Styles/Icons etc. to this renderer's selectors.
+ private static final Map<String, String> _RESOURCE_KEY_MAP;
+
+ static
+ {
+ _RESOURCE_KEY_MAP = new HashMap<String, String>();
+
+ // translation keys
+ _RESOURCE_KEY_MAP.put("af_panelHeader.INFORMATION",
+ "af_messages.INFORMATION");
+ _RESOURCE_KEY_MAP.put("af_panelHeader.WARNING",
+ "af_messages.WARNING");
+ _RESOURCE_KEY_MAP.put("af_panelHeader.ERROR",
+ "af_messages.ERROR");
+ _RESOURCE_KEY_MAP.put("af_panelHeader.CONFIRMATION",
+ "af_messages.CONFIRMATION");
+ // icons
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_ERROR_ICON_NAME,
+ SkinSelectors.AF_MESSAGES_ERROR_ICON_NAME);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_WARNING_ICON_NAME,
+ SkinSelectors.AF_MESSAGES_WARNING_ICON_NAME);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_INFO_ICON_NAME,
+ SkinSelectors.AF_MESSAGES_INFO_ICON_NAME);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_CONFIRMATION_ICON_NAME,
+ SkinSelectors.AF_MESSAGES_CONFIRMATION_ICON_NAME);
+
+ // styles
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_ERROR_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_ERROR_STYLE_CLASS);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_HEADER_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_HEADER_STYLE_CLASS);
+
+ // We forced the use of 'light' style above, so now map it
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_LIGHT_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_STYLE_CLASS);
+
+ // frame styles
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_START_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_TOP_START_STYLE_CLASS);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_TOP_STYLE_CLASS);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_TOP_END_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_TOP_END_STYLE_CLASS);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_START_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_START_STYLE_CLASS);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_END_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_END_STYLE_CLASS);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_START_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_BOTTOM_START_STYLE_CLASS);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_BOTTOM_STYLE_CLASS);
+ _RESOURCE_KEY_MAP.put(SkinSelectors.AF_PANEL_BOX_BOTTOM_END_STYLE_CLASS,
+ SkinSelectors.AF_MESSAGES_BOTTOM_END_STYLE_CLASS);
+ }
+
+}