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.data.provider.SortCriteria;
044: import com.sun.rave.web.ui.component.Table;
045: import com.sun.rave.web.ui.component.TableColumn;
046: import com.sun.rave.web.ui.component.TableFooter;
047: import com.sun.rave.web.ui.component.TableRowGroup;
048: import com.sun.rave.web.ui.theme.Theme;
049: import com.sun.rave.web.ui.theme.ThemeStyles;
050: import com.sun.rave.web.ui.util.LogUtil;
051: import com.sun.rave.web.ui.util.RenderingUtilities;
052: import com.sun.rave.web.ui.util.ThemeUtilities;
053:
054: import java.io.IOException;
055: import java.util.Iterator;
056:
057: import javax.faces.component.UIComponent;
058: import javax.faces.context.FacesContext;
059: import javax.faces.context.ResponseWriter;
060: import javax.faces.render.Renderer;
061:
062: /**
063: * This class renders TableFooter components.
064: * <p>
065: * Note: To see the messages logged by this class, set the following global
066: * defaults in your JDK's "jre/lib/logging.properties" file.
067: * </p><p><pre>
068: * java.util.logging.ConsoleHandler.level = FINE
069: * com.sun.rave.web.ui.renderer.TableFooterRenderer.level = FINE
070: * </pre></p>
071: */
072: public class TableFooterRenderer extends Renderer {
073: /**
074: * The set of String pass-through attributes to be rendered.
075: * <p>
076: * Note: The WIDTH, HEIGHT, and BGCOLOR attributes are all deprecated (in
077: * the HTML 4.0 spec) in favor of style sheets. In addition, the DIR and
078: * LANG attributes are not cuurently supported.
079: * </p>
080: */
081: private static final String stringAttributes[] = { "abbr", //NOI18N
082: "align", //NOI18N
083: "axis", //NOI18N
084: "bgColor", //NOI18N
085: "char", //NOI18N
086: "charOff", //NOI18N
087: "dir", //NOI18N
088: "headers", //NOI18N
089: "height", //NOI18N
090: "lang", //NOI18N
091: "onClick", //NOI18N
092: "onDblClick", //NOI18N
093: "onKeyDown", //NOI18N
094: "onKeyPress", //NOI18N
095: "onKeyUp", //NOI18N
096: "onMouseDown", //NOI18N
097: "onMouseUp", //NOI18N
098: "onMouseMove", //NOI18N
099: "onMouseOut", //NOI18N
100: "onMouseOver", //NOI18N
101: "style", //NOI18N
102: "valign", //NOI18N
103: "width" }; //NOI18N
104:
105: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
106: // Renderer methods
107: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
108:
109: /**
110: * Render the beginning of the specified UIComponent to the output stream or
111: * writer associated with the response we are creating.
112: *
113: * @param context FacesContext for the current request.
114: * @param component UIComponent to be rendered.
115: *
116: * @exception IOException if an input/output error occurs.
117: * @exception NullPointerException if context or component is null.
118: */
119: public void encodeBegin(FacesContext context, UIComponent component)
120: throws IOException {
121: if (context == null || component == null) {
122: log("encodeBegin", //NOI18N
123: "Cannot render, FacesContext or UIComponent is null"); //NOI18N
124: throw new NullPointerException();
125: }
126: if (!component.isRendered()) {
127: log("encodeBegin",
128: "Component not rendered, nothing to display"); //NOI18N
129: return;
130: }
131:
132: TableFooter footer = (TableFooter) component;
133: ResponseWriter writer = context.getResponseWriter();
134: renderEnclosingTagStart(context, footer, writer);
135: }
136:
137: /**
138: * Render the children of the specified UIComponent to the output stream or
139: * writer associated with the response we are creating.
140: *
141: * @param context FacesContext for the current request.
142: * @param component UIComponent to be decoded.
143: *
144: * @exception IOException if an input/output error occurs.
145: * @exception NullPointerException if context or component is null.
146: */
147: public void encodeChildren(FacesContext context,
148: UIComponent component) throws IOException {
149: if (context == null || component == null) {
150: log("encodeChildren", //NOI18N
151: "Cannot render, FacesContext or UIComponent is null"); //NOI18N
152: throw new NullPointerException();
153: }
154: if (!component.isRendered()) {
155: log("encodeChildren",
156: "Component not rendered, nothing to display"); //NOI18N
157: return;
158: }
159:
160: TableFooter footer = (TableFooter) component;
161: ResponseWriter writer = context.getResponseWriter();
162:
163: // Render footers.
164: if (footer.isGroupFooter()) {
165: renderGroupFooter(context, footer, writer);
166: } else if (footer.isTableColumnFooter()) {
167: renderTableColumnFooter(context, footer, writer);
168: } else if (footer.isTableFooter()) {
169: renderTableFooter(context, footer, writer);
170: } else {
171: renderColumnFooter(context, footer, writer);
172: }
173: }
174:
175: /**
176: * Render the ending of the specified UIComponent to the output stream or
177: * writer associated with the response we are creating.
178: *
179: * @param context FacesContext for the current request.
180: * @param component UIComponent to be rendered.
181: *
182: * @exception IOException if an input/output error occurs.
183: * @exception NullPointerException if context or component is null.
184: */
185: public void encodeEnd(FacesContext context, UIComponent component)
186: throws IOException {
187: if (context == null || component == null) {
188: log("encodeChildren", //NOI18N
189: "Cannot render, FacesContext or UIComponent is null"); //NOI18N
190: throw new NullPointerException();
191: }
192: if (!component.isRendered()) {
193: log("encodeChildren",
194: "Component not rendered, nothing to display"); //NOI18N
195: return;
196: }
197:
198: TableFooter footer = (TableFooter) component;
199: ResponseWriter writer = context.getResponseWriter();
200: renderEnclosingTagEnd(context, footer, writer);
201: }
202:
203: /**
204: * Return a flag indicating whether this Renderer is responsible
205: * for rendering the children the component it is asked to render.
206: * The default implementation returns false.
207: */
208: public boolean getRendersChildren() {
209: return true;
210: }
211:
212: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
213: // Footer methods
214: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
215:
216: /**
217: * Render column footer for TableFooter components.
218: *
219: * @param context FacesContext for the current request.
220: * @param component TableFooter to be rendered.
221: * @param writer ResponseWriter to which the component should be rendered.
222: *
223: * @exception IOException if an input/output error occurs.
224: */
225: protected void renderColumnFooter(FacesContext context,
226: TableFooter component, ResponseWriter writer)
227: throws IOException {
228: if (component == null) {
229: log("renderColumnFooter", //NOI18N
230: "Cannot render column footer, TableFooter is null"); //NOI18N
231: return;
232: }
233:
234: // Render facet.
235: TableColumn col = component.getTableColumnAncestor();
236: UIComponent facet = (col != null) ? component
237: .getFacet(TableColumn.FOOTER_FACET) : null;
238: if (facet != null && facet.isRendered()) {
239: RenderingUtilities.renderComponent(facet, context);
240: } else {
241: writer.startElement("span", component); //NOI18N
242: writer.writeAttribute(
243: "class", //NOI18N
244: getTheme().getStyleClass(
245: ThemeStyles.TABLE_GROUP_COL_FOOTER_TEXT),
246: null);
247:
248: // Render footer text.
249: if (col != null && col.getFooterText() != null) {
250: writer.writeText(col.getFooterText(), null);
251: }
252: writer.endElement("span"); //NOI18N
253: }
254: }
255:
256: /**
257: * Render group footer for TableFooter components.
258: *
259: * @param context FacesContext for the current request.
260: * @param component TableFooter to be rendered.
261: * @param writer ResponseWriter to which the component should be rendered.
262: *
263: * @exception IOException if an input/output error occurs.
264: */
265: protected void renderGroupFooter(FacesContext context,
266: TableFooter component, ResponseWriter writer)
267: throws IOException {
268: if (component == null) {
269: log("renderGroupFooter", //NOI18N
270: "Cannot render group footer, TableFooter is null"); //NOI18N
271: return;
272: }
273:
274: // Render facet.
275: TableRowGroup group = component.getTableRowGroupAncestor();
276: UIComponent facet = (group != null) ? group
277: .getFacet(TableRowGroup.FOOTER_FACET) : null;
278: if (facet != null && facet.isRendered()) {
279: RenderingUtilities.renderComponent(facet, context);
280: } else {
281: writer.startElement("span", component); //NOI18N
282: writer.writeAttribute("class", //NOI18N
283: getTheme().getStyleClass(
284: ThemeStyles.TABLE_GROUP_FOOTER_TEXT), null);
285:
286: // Render text.
287: if (group.getFooterText() != null) {
288: writer.writeText(group.getFooterText(), null);
289: }
290: writer.endElement("span"); //NOI18N
291: }
292: }
293:
294: /**
295: * Render table column footer for TableFooter components.
296: *
297: * @param context FacesContext for the current request.
298: * @param component TableFooter to be rendered.
299: * @param writer ResponseWriter to which the component should be rendered.
300: *
301: * @exception IOException if an input/output error occurs.
302: */
303: protected void renderTableColumnFooter(FacesContext context,
304: TableFooter component, ResponseWriter writer)
305: throws IOException {
306: if (component == null) {
307: log("renderTableColumnFooter", //NOI18N
308: "Cannot render table column footer, TableFooter is null"); //NOI18N
309: return;
310: }
311:
312: // Render facet.
313: TableColumn col = component.getTableColumnAncestor();
314: UIComponent facet = (col != null) ? col
315: .getFacet(TableColumn.TABLE_FOOTER_FACET) : null;
316: if (facet != null && facet.isRendered()) {
317: RenderingUtilities.renderComponent(facet, context);
318: } else {
319: writer.startElement("span", component); //NOI18N
320: writer.writeAttribute("class", //NOI18N
321: getTheme().getStyleClass(
322: ThemeStyles.TABLE_COL_FOOTER_TEXT), null);
323:
324: // Get TableColumn component.
325: if (col != null && col.getTableFooterText() != null) {
326: writer.writeText(col.getTableFooterText(), null);
327: }
328: writer.endElement("span"); //NOI18N
329: }
330: }
331:
332: /**
333: * Render table footer for TableFooter components.
334: *
335: * @param context FacesContext for the current request.
336: * @param component TableFooter to be rendered.
337: * @param writer ResponseWriter to which the component should be rendered.
338: *
339: * @exception IOException if an input/output error occurs.
340: */
341: protected void renderTableFooter(FacesContext context,
342: TableFooter component, ResponseWriter writer)
343: throws IOException {
344: if (component == null) {
345: log("renderTableFooter", //NOI18N
346: "Cannot render table footer, TableFooter is null"); //NOI18N
347: return;
348: }
349:
350: Table table = component.getTableAncestor();
351: if (table == null) {
352: log("renderTableFooter", //NOI18N
353: "Cannot render table footer, Table is null"); //NOI18N
354: return;
355: }
356:
357: // Render facet.
358: UIComponent facet = table.getFacet(Table.TABLE_FOOTER_FACET);
359: if (facet != null && facet.isRendered()) {
360: RenderingUtilities.renderComponent(facet, context);
361: } else {
362: Theme theme = getTheme();
363:
364: // Get hidden selected rows text.
365: String hiddenSelectionsText = table.isHiddenSelectedRows() ? theme
366: .getMessage("table.hiddenSelections", //NOI18N
367: new String[] { Integer.toString(table
368: .getHiddenSelectedRowsCount()) })
369: : null;
370:
371: // If both footer and hidden selected rows are not null, the
372: // table footer is left aigned and hidden selected rows is right
373: // aligned. Otherwise, text should appear centered.
374: if (hiddenSelectionsText != null
375: && table.getFooterText() != null) {
376: writer.startElement("span", component); //NOI18N
377: writer
378: .writeAttribute(
379: "class", //NOI18N
380: theme
381: .getStyleClass(ThemeStyles.TABLE_FOOTER_LEFT),
382: null);
383: writer.writeText(table.getFooterText(), null);
384: writer.endElement("span"); //NOI18N
385: writer.startElement("span", component); //NOI18N
386: writer
387: .writeAttribute(
388: "class", //NOI18N
389: theme
390: .getStyleClass(ThemeStyles.TABLE_FOOTER_MESSAGE_SPAN),
391: null);
392: writer.writeText(hiddenSelectionsText, null);
393: writer.endElement("span"); //NOI18N
394: } else {
395: writer.startElement("span", component); //NOI18N
396: writer
397: .writeAttribute(
398: "class", //NOI18N
399: theme
400: .getStyleClass(ThemeStyles.TABLE_FOOTER_TEXT),
401: null);
402: writer
403: .writeText(
404: (table.getFooterText() != null) ? table
405: .getFooterText()
406: : hiddenSelectionsText, null);
407: writer.endElement("span"); //NOI18N
408: }
409: }
410: }
411:
412: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
413: // Enclosing tag methods
414: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
415:
416: /**
417: * Render enclosing tag for TableFooter components.
418: *
419: * @param context FacesContext for the current request.
420: * @param component TableFooter to be rendered.
421: * @param writer ResponseWriter to which the component should be rendered.
422: *
423: * @exception IOException if an input/output error occurs.
424: */
425: protected void renderEnclosingTagStart(FacesContext context,
426: TableFooter component, ResponseWriter writer)
427: throws IOException {
428: if (component == null) {
429: log("renderEnclosingTagStart", //NOI18N
430: "Cannot render enclosing tag, TableFooter is null"); //NOI18N
431: return;
432: }
433:
434: writer.writeText("\n", null); //NOI18N
435: writer.startElement("td", component); //NOI18N
436: writer.writeAttribute("id", component.getClientId(context),
437: null); //NOI18N
438:
439: // Render style class.
440: String extraHtml = RenderingUtilities.renderStyleClass(context,
441: writer, component, getStyleClass(component), component
442: .getExtraHtml());
443:
444: // Render colspan.
445: if (component.getColSpan() > -1
446: && (extraHtml == null || extraHtml.indexOf("colspan=") == -1)) { //NOI18N
447: writer.writeAttribute("colspan", //NOI18N
448: Integer.toString(component.getColSpan()), null); //NOI18N
449: }
450:
451: // Render rowspan.
452: if (component.getRowSpan() > -1
453: && (extraHtml == null || extraHtml.indexOf("rowspan=") == -1)) { //NOI18N
454: writer.writeAttribute("rowspan", //NOI18N
455: Integer.toString(component.getRowSpan()), null); //NOI18N
456: }
457:
458: // Render nowrap.
459: if (component.isNoWrap()
460: && (extraHtml == null || extraHtml.indexOf("nowrap=") == -1)) { //NOI18N
461: writer.writeAttribute("nowrap", "nowrap", null); //NOI18N
462: }
463:
464: // Render tooltip.
465: if (component.getToolTip() != null
466: && (extraHtml == null || extraHtml.indexOf("title=") == -1)) { //NOI18N
467: writer.writeAttribute("title", component.getToolTip(),
468: "toolTip"); //NOI18N
469: }
470:
471: // Render pass through attributes.
472: RenderingUtilities.writeStringAttributes(component, writer,
473: stringAttributes, extraHtml);
474: }
475:
476: /**
477: * Render enclosing tag for TableFooter components.
478: *
479: * @param context FacesContext for the current request.
480: * @param component TableFooter to be rendered.
481: * @param writer ResponseWriter to which the component should be rendered.
482: *
483: * @exception IOException if an input/output error occurs.
484: */
485: protected void renderEnclosingTagEnd(FacesContext context,
486: TableFooter component, ResponseWriter writer)
487: throws IOException {
488: if (component == null) {
489: log("renderEnclosingTagEnd", //NOI18N
490: "Cannot render enclosing tag, TableFooter is null"); //NOI18N
491: return;
492: }
493: writer.endElement("td"); //NOI18N
494: }
495:
496: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
497: // Private methods
498: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
499:
500: /**
501: * Helper method to get style class for TableFooter components.
502: *
503: * @param component TableFooter to be rendered
504: * @return The style class.
505: */
506: private String getStyleClass(TableFooter component) {
507: String styleClass = null;
508: if (component == null) {
509: log("getStyleClass", //NOI18N
510: "Cannot obtain style class, TableFooter is null"); //NOI18N
511: return styleClass;
512: }
513:
514: // Get style class.
515: if (component.isTableFooter()) {
516: styleClass = ThemeStyles.TABLE_FOOTER;
517: } else if (component.isGroupFooter()) {
518: styleClass = ThemeStyles.TABLE_GROUP_FOOTER;
519: } else {
520: TableColumn col = component.getTableColumnAncestor();
521: if (col != null && col.isSpacerColumn()) {
522: styleClass = (component.isTableColumnFooter()) ? ThemeStyles.TABLE_COL_FOOTER_SPACER
523: : ThemeStyles.TABLE_TD_SPACER;
524: } else if (component.getSortLevel() == 1) {
525: styleClass = (component.isTableColumnFooter()) ? ThemeStyles.TABLE_COL_FOOTER_SORT
526: : ThemeStyles.TABLE_GROUP_COL_FOOTER_SORT;
527: } else {
528: styleClass = (component.isTableColumnFooter()) ? ThemeStyles.TABLE_COL_FOOTER
529: : ThemeStyles.TABLE_GROUP_COL_FOOTER;
530: }
531: }
532: return getTheme().getStyleClass(styleClass);
533: }
534:
535: /** Helper method to get Theme objects. */
536: private Theme getTheme() {
537: return ThemeUtilities.getTheme(FacesContext
538: .getCurrentInstance());
539: }
540:
541: /**
542: * Log fine messages.
543: */
544: private void log(String method, String message) {
545: // Get class.
546: Class clazz = this .getClass();
547: if (LogUtil.fineEnabled(clazz)) {
548: // Log method name and message.
549: LogUtil.fine(clazz, clazz.getName() + "." + method + ": "
550: + message); //NOI18N
551: }
552: }
553: }
|