001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package com.sun.rave.web.ui.renderer;
042:
043: import com.sun.rave.web.ui.component.Hyperlink;
044: import java.io.IOException;
045: import java.util.Properties;
046: import java.util.List;
047:
048: import javax.faces.component.UIComponent;
049: import javax.faces.context.FacesContext;
050: import javax.faces.context.ResponseWriter;
051:
052: import com.sun.rave.web.ui.component.Alert;
053: import com.sun.rave.web.ui.component.IconHyperlink;
054: import com.sun.rave.web.ui.component.util.Util;
055: import com.sun.rave.web.ui.theme.Theme;
056: import com.sun.rave.web.ui.theme.ThemeImages;
057: import com.sun.rave.web.ui.theme.ThemeStyles;
058: import com.sun.rave.web.ui.util.RenderingUtilities;
059: import com.sun.rave.web.ui.util.ThemeUtilities;
060:
061: /**
062: * <p>Renderer for an {@link Alert} component.</p>
063: *
064: */
065: public class AlertRenderer extends AbstractRenderer {
066:
067: /**
068: * <p>The different types or categories of an alert.</p>
069: */
070: public static final String ALERT_TYPE_ERROR = "error"; //NOI18N
071: public static final String ALERT_TYPE_WARN = "warning"; //NOI18N
072: public static final String ALERT_TYPE_INFO = "information"; //NOI18N
073: public static final String ALERT_TYPE_SUCCESS = "success"; //NOI18N
074: /**
075: * <p>The default error type - if none is specified.</p>
076: */
077: public static final String ALERT_TYPE_DEFAULT = ALERT_TYPE_ERROR; //NOI18N
078:
079: private static final String ICON_HYPERLINK_FACTORY = "com.sun.rave.web.ui.component.util.factories.IconHyperlinkFactory"; //NOI18N
080:
081: /** Creates a new instance of AlertRenderer */
082: public AlertRenderer() {
083: // default constructor
084: }
085:
086: public boolean getRendersChildren() {
087: return true;
088: }
089:
090: public void encodeChildren(FacesContext context,
091: UIComponent component) throws IOException {
092: //purposefully don't want to do anything here!
093:
094: }
095:
096: /**
097: * Renders the outer div which contains the alert.
098: *
099: * @param context The current FacesContext
100: * @param alert The Alert object to use
101: * @param writer The current ResponseWriter
102: *
103: * @exception IOException if an input/output error occurs
104: */
105: protected void renderOuterDiv(FacesContext context, Alert alert,
106: ResponseWriter writer) throws IOException {
107: String styleClass = alert.getStyleClass();
108: String style = alert.getStyle();
109: String id = alert.getClientId(context);
110:
111: writer.startElement("div", alert); //NOI18N
112:
113: // Write a id only if a style/class was specified?
114: if (id != null) {
115: writer.writeAttribute("id", id, null); //NOI18N
116: }
117:
118: if (style != null) {
119: writer.writeAttribute("style", style, null); //NOI18N
120: }
121:
122: RenderingUtilities.renderStyleClass(context, writer,
123: (UIComponent) alert, styleClass);
124: }
125:
126: /**
127: * Renders the attributes for the outer table containing the inline alert.
128: * TODO: Use div's instead of tables for layout as soon as I can find a
129: * solution that works for IE.
130: *
131: * @param context The current FacesContext
132: * @param alert The Alert object to use
133: * @param theme The Theme to use
134: * @param writer The current ResponseWriter
135: *
136: * @exception IOException if an input/output error occurs
137: */
138: protected void renderOpeningTable(FacesContext context,
139: Alert alert, Theme theme, ResponseWriter writer)
140: throws IOException {
141: writer.startElement("table", alert); //NOI18N
142:
143: // <RAVE>
144: // align attribute is deprecated and it causes incosistent result in IE and Mozilla when it is set (see bug 6327647)
145: //writer.writeAttribute("align", "center", null); //NOI18N
146: // <RAVE>
147: writer.writeAttribute("border", "0", null); //NOI18N
148: writer.writeAttribute("cellspacing", "0", null); //NOI18N
149: writer.writeAttribute("cellpadding", "0", null); //NTOI18N
150: writer.writeAttribute("title", "", null); //NOI18N
151:
152: // Set the containing table style based on the theme
153: String tableStyle = theme
154: .getStyleClass(ThemeStyles.ALERT_TABLE);
155: writer.writeAttribute("class", tableStyle, null); //NOI18N
156: writer.writeText("\n", null); //NOI18N
157:
158: writer.startElement("tr", alert); //NOI18N
159: writer.writeText("\n", null); //NOI18N
160:
161: writer.startElement("td", alert); //NOI18N
162: writer.writeAttribute("valign", "middle", null); //NOI18N
163: writer.writeText("\n", null); //NOI18N
164: }
165:
166: /**
167: * Renders the icon associated with an inline alert message.
168: *
169: * @param context The current FacesContext
170: * @param alert The Alert object to use
171: * @param theme The theme to use
172: * @param type The type of alert. Default is ALERT_TYPE_ERROR.
173: * @param writer The current ResponseWriter
174: *
175: * @exception IOException if an input/output error occurs
176: */
177: protected void renderAlertIcon(FacesContext context, Alert alert,
178: String type, Theme theme, ResponseWriter writer)
179: throws IOException {
180: UIComponent alertIcon = alert.getAlertIcon();
181: RenderingUtilities.renderComponent(alertIcon, context);
182: }
183:
184: /**
185: * Renders the summary message of the inline alert.
186: *
187: * @param alert The Alert object to use
188: * @param writer The current ResponseWriter
189: *
190: * @exception IOException if an input/output error occurs
191: */
192: protected void renderAlertSummaryText(Alert alert,
193: ResponseWriter writer) throws IOException {
194: // Render the summary text
195: String summary = alert.getSummary();
196:
197: // Check if it should be HTML escaped (true by default).
198: writer.writeText(summary, null);
199: }
200:
201: /**
202: * Renders the optional detail message of the inline alert.
203: *
204: * @param alert The Alert object to use
205: * @param theme The theme to use
206: * @param writer The current ResponseWriter
207: *
208: * @exception IOException if an input/output error occurs
209: */
210: protected void renderAlertDetailArea(FacesContext context,
211: Alert alert, Theme theme, ResponseWriter writer)
212: throws IOException {
213: // Get the detail text
214: String detail = alert.getDetail();
215:
216: // Get the children, if any.
217: List children = alert.getChildren();
218: if ((detail == null || detail.trim().length() == 0)
219: && children.size() <= 0)
220: return;
221:
222: // Set the style
223: writer.startElement("div", alert); //NOI18N
224: writer.writeAttribute(
225: "class", // NOI18N
226: theme.getStyleClass(ThemeStyles.ALERT_MESSAGE_TEXT),
227: null);
228:
229: // Check if it should be HTML escaped (true by default).
230: if (detail != null) {
231: writer.writeText(detail, null);
232: }
233:
234: // render any children
235: super .encodeChildren(context, alert);
236: // Close the div
237: writer.endElement("div"); //NOI18N
238: writer.writeText("\n", null); //NOI18N
239: }
240:
241: /**
242: * Renders the optional link at the end of the alert.
243: *
244: * @param context The current FacesContext
245: * @param alert The Alert object to use
246: * @param writer The current ResponseWriter
247: *
248: * @exception IOException if an input/output error occurs
249: */
250: protected void renderAlertLink(FacesContext context, Alert alert,
251: Theme theme, ResponseWriter writer) throws IOException {
252: UIComponent link = alert.getAlertLink();
253: if (link == null)
254: return;
255: if (Hyperlink.class.isAssignableFrom(link.getClass())
256: && ((Hyperlink) link).getText() == null
257: && ((Hyperlink) link).getUrl() == null)
258: return;
259: writer.startElement("div", alert); //NOI18N
260: writer.writeAttribute("class", //NOI18N
261: theme.getStyleClass(ThemeStyles.ALERT_LINK_DIV), null);
262: RenderingUtilities.renderComponent(link, context);
263: writer.endElement("div"); //NOI18N
264: }
265:
266: /**
267: * Renders the optional detail message of the inline alert.
268: *
269: * @param writer The current ResponseWriter
270: *
271: * @exception IOException if an input/output error occurs
272: */
273: protected void renderClosingTags(ResponseWriter writer)
274: throws IOException {
275: writer.writeText("\n", null); //NOI18N
276: writer.endElement("td"); //NOI18N
277: writer.endElement("tr"); //NOI18N
278: writer.endElement("table"); //NOI18N
279: writer.endElement("div"); //NOI18N
280: writer.writeText("\n", null); //NOI18N
281: }
282:
283: /**
284: * Renders the inline alert component.
285: *
286: * @param context The current FacesContext
287: * @param component The Alert object to use
288: * @param writer The current ResponseWriter
289: *
290: * @exception IOException if an input/output error occurss
291: */
292: protected void renderEnd(FacesContext context,
293: UIComponent component, ResponseWriter writer)
294: throws IOException {
295: // Render end of alert
296: Alert alert = (Alert) component;
297: String summary = alert.getSummary();
298:
299: // If a summary message is not specified, nothing to render.
300: if (summary == null || summary.trim().length() == 0)
301: return;
302:
303: // Get the theme
304: Theme theme = ThemeUtilities.getTheme(context);
305:
306: // Render the outer div that wraps the alert
307: renderOuterDiv(context, alert, writer);
308:
309: // Render the opening table
310: renderOpeningTable(context, alert, theme, writer);
311:
312: // Get the text style based on the type of alert
313: String type = alert.getType();
314: // Set the default type
315: if (type == null)
316: type = ALERT_TYPE_DEFAULT;
317: type = type.toLowerCase();
318:
319: String textStyle = getAlertTextStyle(type, theme);
320: writer.startElement("div", alert); //NOI18N
321: writer.writeAttribute("class", textStyle, null); //NOI18N
322:
323: // Render the alert icon
324: renderAlertIcon(context, alert, type, theme, writer);
325:
326: // Render the summary text
327: renderAlertSummaryText(alert, writer);
328:
329: // Close the div
330: writer.endElement("div"); //NOI18N
331: writer.writeText("\n", null); //NOI18N
332:
333: // Render the detailed text
334: renderAlertDetailArea(context, alert, theme, writer);
335: // Render the optional link, if specified
336: renderAlertLink(context, alert, theme, writer);
337:
338: // Render the closing tags
339: renderClosingTags(writer);
340: }
341:
342: // Private helper methods.
343:
344: /**
345: * Create an alert link component with the apecified properties
346: * The link returned includes the "icon" associated the link.
347: *
348: * @param alert The alert object
349: * @param text The alert link text
350: * @param url The alert link url
351: * @param theme The theme to use
352: *
353: * @return the hyperlink
354: */
355: private IconHyperlink getAlertLink(Alert alert, String text,
356: String url, Theme theme) {
357: // Assign properties
358: Properties props = new Properties();
359: props.setProperty("styleClass", //NOI18N
360: theme.getStyleClass(ThemeStyles.ALERT_LINK));
361: props.setProperty("text", text); //NOI18N
362: props.setProperty("textPosition", "right"); //NOI18N
363: props.setProperty("icon", ThemeImages.HREF_LINK); //NOI18N
364: props.put("border", new Integer(0));
365: props.setProperty("alt", ""); //NOI18N
366: props.setProperty("url", url); //NOI18N
367: String prop = alert.getLinkTarget();
368: if (prop != null && prop.length() > 0) {
369: props.setProperty("target", prop); //NOI18N
370: }
371: prop = alert.getLinkToolTip();
372: if (prop != null && prop.length() > 0) {
373: props.setProperty("toolTip", prop); //NOI18N
374: }
375: IconHyperlink link = (IconHyperlink) Util.getChild(alert, alert
376: .getId()
377: + "_alertLink", ICON_HYPERLINK_FACTORY, //NOI18N
378: props); //NOI18N
379: return link;
380: }
381:
382: /**
383: * Return the text style for the inline alert message, based on the
384: * type of alert.
385: *
386: * @param type The type of alert. Default is ALERT_TYPE_ERROR.
387: * @param theme The theme to use.
388: *
389: * @return The alert text style.
390: */
391: private String getAlertTextStyle(String type, Theme theme) {
392: String style;
393:
394: if (type.equals(ALERT_TYPE_INFO)) {
395: // Info
396: style = theme
397: .getStyleClass(ThemeStyles.ALERT_INFORMATION_TEXT);
398: } else if (type.equals(ALERT_TYPE_SUCCESS)) {
399: // Success - no style defined.
400: style = theme
401: .getStyleClass(ThemeStyles.ALERT_INFORMATION_TEXT);
402: } else if (type.equals(ALERT_TYPE_WARN)) {
403: // Warning
404: style = theme.getStyleClass(ThemeStyles.ALERT_WARNING_TEXT);
405: } else {
406: // Error
407: style = theme.getStyleClass(ThemeStyles.ALERT_ERROR_TEXT);
408: }
409: return style;
410: }
411: }
|