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.TableHeader;
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 TableHeader 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.TableHeaderRenderer.level = FINE
070: * </pre></p>
071: */
072: public class TableHeaderRenderer 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: "scope", //NOI18N
102: "style", //NOI18N
103: "valign", //NOI18N
104: "width" }; //NOI18N
105:
106: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
107: // Renderer methods
108: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
109:
110: /**
111: * Render the beginning of the specified UIComponent to the output stream or
112: * writer associated with the response we are creating.
113: *
114: * @param context FacesContext for the current request.
115: * @param component UIComponent to be rendered.
116: *
117: * @exception IOException if an input/output error occurs.
118: * @exception NullPointerException if context or component is null.
119: */
120: public void encodeBegin(FacesContext context, UIComponent component)
121: throws IOException {
122: if (context == null || component == null) {
123: log("encodeBegin", //NOI18N
124: "Cannot render, FacesContext or UIComponent is null"); //NOI18N
125: throw new NullPointerException();
126: }
127: if (!component.isRendered()) {
128: log("encodeBegin",
129: "Component not rendered, nothing to display"); //NOI18N
130: return;
131: }
132:
133: TableHeader header = (TableHeader) component;
134: ResponseWriter writer = context.getResponseWriter();
135: renderEnclosingTagStart(context, header, writer);
136: }
137:
138: /**
139: * Render the children of the specified UIComponent to the output stream or
140: * writer associated with the response we are creating.
141: *
142: * @param context FacesContext for the current request.
143: * @param component UIComponent to be decoded.
144: *
145: * @exception IOException if an input/output error occurs.
146: * @exception NullPointerException if context or component is null.
147: */
148: public void encodeChildren(FacesContext context,
149: UIComponent component) throws IOException {
150: if (context == null || component == null) {
151: log("encodeChildren", //NOI18N
152: "Cannot render, FacesContext or UIComponent is null"); //NOI18N
153: throw new NullPointerException();
154: }
155: if (!component.isRendered()) {
156: log("encodeChildren",
157: "Component not rendered, nothing to display"); //NOI18N
158: return;
159: }
160:
161: TableHeader header = (TableHeader) component;
162: ResponseWriter writer = context.getResponseWriter();
163:
164: // Render headers.
165: if (header.isGroupHeader()) {
166: renderGroupHeader(context, header, writer);
167: } else if (header.isSelectHeader()) {
168: renderSelectHeader(context, header, writer);
169: } else if (header.isSortHeader()) {
170: renderSortHeader(context, header, writer);
171: } else {
172: renderColumnHeader(context, header, writer);
173: }
174: }
175:
176: /**
177: * Render the ending of the specified UIComponent to the output stream or
178: * writer associated with the response we are creating.
179: *
180: * @param context FacesContext for the current request.
181: * @param component UIComponent to be rendered.
182: *
183: * @exception IOException if an input/output error occurs.
184: * @exception NullPointerException if context or component is null.
185: */
186: public void encodeEnd(FacesContext context, UIComponent component)
187: throws IOException {
188: if (context == null || component == null) {
189: log("encodeEnd", //NOI18N
190: "Cannot render, FacesContext or UIComponent is null"); //NOI18N
191: throw new NullPointerException();
192: }
193: if (!component.isRendered()) {
194: log("encodeEnd",
195: "Component not rendered, nothing to display"); //NOI18N
196: return;
197: }
198:
199: TableHeader header = (TableHeader) component;
200: ResponseWriter writer = context.getResponseWriter();
201: renderEnclosingTagEnd(context, header, writer);
202: }
203:
204: /**
205: * Return a flag indicating whether this Renderer is responsible
206: * for rendering the children the component it is asked to render.
207: * The default implementation returns false.
208: */
209: public boolean getRendersChildren() {
210: return true;
211: }
212:
213: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
214: // Header methods
215: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
216:
217: /**
218: * Render column headers for TableHeader components.
219: *
220: * @param context FacesContext for the current request.
221: * @param component TableHeader to be rendered.
222: * @param writer ResponseWriter to which the component should be rendered.
223: *
224: * @exception IOException if an input/output error occurs.
225: */
226: protected void renderColumnHeader(FacesContext context,
227: TableHeader component, ResponseWriter writer)
228: throws IOException {
229: if (component == null) {
230: log("renderColumnHeader", //NOI18N
231: "Cannot render column header, TableHeader is null"); //NOI18N
232: return;
233: }
234:
235: // Get facet.
236: TableColumn col = component.getTableColumnAncestor();
237: UIComponent facet = (col != null) ? col
238: .getFacet(TableColumn.HEADER_FACET) : null;
239: if (facet != null && facet.isRendered()) {
240: RenderingUtilities.renderComponent(facet, context);
241: } else {
242: // Get style for nested column headers.
243: TableColumn parent = (col != null) ? col
244: .getTableColumnAncestor() : null;
245: Iterator kids = (col != null) ? col
246: .getTableColumnChildren() : null;
247: String styleClass = (kids != null && kids.hasNext()) ? ThemeStyles.TABLE_MULTIPLE_HEADER_TEXT
248: : ThemeStyles.TABLE_HEADER_TEXT;
249:
250: // If TableColumn has a parent, then it is a leaf node.
251: if (parent != null) {
252: writer.writeText("\n", null); //NOI18N
253: writer.startElement("table", component); //NOI18N
254: writer.writeAttribute("class", //NOI18N
255: getTheme().getStyleClass(
256: ThemeStyles.TABLE_HEADER_TABLE), null);
257: writer.writeAttribute("border", "0", null); //NOI18N
258: writer
259: .writeAttribute("cellpadding", "0",
260: "cellPadding"); //NOI18N
261: writer
262: .writeAttribute("cellspacing", "0",
263: "cellSpacing"); //NOI18N
264: writer.writeText("\n", null); //NOI18N
265: writer.startElement("tr", component); //NOI18N
266: writer.writeText("\n", null); //NOI18N
267: writer.startElement("td", component); //NOI18N
268: writer.startElement("span", component); //NOI18N
269: writer.writeAttribute("class", //NOI18N
270: getTheme().getStyleClass(styleClass), null);
271:
272: // Render header text.
273: if (col != null && col.getHeaderText() != null) {
274: writer.writeText(col.getHeaderText(), null); //NOI18N
275: }
276: writer.endElement("span"); //NOI18N
277: writer.endElement("td"); //NOI18N
278: writer.endElement("tr"); //NOI18N
279: writer.endElement("table"); //NOI18N
280: } else {
281: writer.startElement("span", component); //NOI18N
282: writer.writeAttribute("class", //NOI18N
283: getTheme().getStyleClass(styleClass), null);
284:
285: // Render header text.
286: if (col != null && col.getHeaderText() != null) {
287: writer.writeText(col.getHeaderText(), null); //NOI18N
288: }
289: writer.endElement("span"); //NOI18N
290: }
291: }
292: }
293:
294: /**
295: * Render select column headers for TableHeader components.
296: *
297: * @param context FacesContext for the current request.
298: * @param component TableHeader 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 renderSelectHeader(FacesContext context,
304: TableHeader component, ResponseWriter writer)
305: throws IOException {
306: if (component == null) {
307: log("renderSelectHeader", //NOI18N
308: "Cannot render select header, TableHeader is null"); //NOI18N
309: return;
310: }
311:
312: // Get facet.
313: TableColumn col = component.getTableColumnAncestor();
314: UIComponent facet = (col != null) ? col
315: .getFacet(TableColumn.HEADER_FACET) : null;
316: if (facet != null && facet.isRendered()) {
317: RenderingUtilities.renderComponent(facet, context);
318: } else {
319: // Render layout table.
320: writer.writeText("\n", null); //NOI18N
321: writer.startElement("table", component); //NOI18N
322: writer.writeAttribute("class", //NOI18N
323: getTheme().getStyleClass(
324: ThemeStyles.TABLE_HEADER_TABLE), null);
325: writer.writeAttribute("border", "0", null); //NOI18N
326: writer.writeAttribute("cellpadding", "0", "cellPadding"); //NOI18N
327: writer.writeAttribute("cellspacing", "0", "cellSpacing"); //NOI18N
328: writer.writeText("\n", null); //NOI18N
329: writer.startElement("tr", component); //NOI18N
330:
331: // Render sort title.
332: writer.writeText("\n", null); //NOI18N
333: writer.startElement("td", component); //NOI18N
334: writer.writeAttribute("align", component.getAlign(), null); //NOI18N
335: RenderingUtilities.renderComponent(component
336: .getSelectSortButton(), context);
337: writer.endElement("td"); //NOI18N
338:
339: // Get sort button.
340: UIComponent child = null;
341: if (component.getSortLevel() > 0) {
342: child = component.getToggleSortButton();
343: } else if (component.getSortCount() > 0) {
344: // Render add button when any sort has been applied.
345: child = component.getAddSortButton();
346: }
347:
348: // Render sort button.
349: if (child != null) {
350: writer.writeText("\n", null); //NOI18N
351: writer.startElement("td", component); //NOI18N
352: RenderingUtilities.renderComponent(child, context);
353: writer.endElement("td"); //NOI18N
354: }
355: writer.endElement("tr"); //NOI18N
356: writer.endElement("table"); //NOI18N
357: }
358: }
359:
360: /**
361: * Render sort column headers for TableHeader components.
362: *
363: * @param context FacesContext for the current request.
364: * @param component TableHeader to be rendered.
365: * @param writer ResponseWriter to which the component should be rendered.
366: *
367: * @exception IOException if an input/output error occurs.
368: */
369: protected void renderSortHeader(FacesContext context,
370: TableHeader component, ResponseWriter writer)
371: throws IOException {
372: if (component == null) {
373: log("renderSortHeader", //NOI18N
374: "Cannot render sort header, TableHeader is null"); //NOI18N
375: return;
376: }
377:
378: // Get facet.
379: TableColumn col = component.getTableColumnAncestor();
380: UIComponent facet = (col != null) ? col
381: .getFacet(TableColumn.HEADER_FACET) : null;
382: if (facet != null && facet.isRendered()) {
383: RenderingUtilities.renderComponent(facet, context);
384: } else {
385: // Render layout table so sort link/button may wrap properly.
386: writer.writeText("\n", null); //NOI18N
387: writer.startElement("table", component); //NOI18N
388: writer.writeAttribute("class", //NOI18N
389: getTheme().getStyleClass(
390: ThemeStyles.TABLE_HEADER_TABLE), null);
391: writer.writeAttribute("border", "0", null); //NOI18N
392: writer.writeAttribute("cellpadding", "0", "cellPadding"); //NOI18N
393: writer.writeAttribute("cellspacing", "0", "cellSpacing"); //NOI18N
394: writer.writeText("\n", null); //NOI18N
395: writer.startElement("tr", component); //NOI18N
396:
397: // Render sort link.
398: if (col != null && col.getHeaderText() != null) {
399: writer.writeText("\n", null); //NOI18N
400: writer.startElement("td", component); //NOI18N
401: writer.writeAttribute("align", //NOI18N
402: component.getAlign(), null); //NOI18N
403: RenderingUtilities.renderComponent(component
404: .getPrimarySortLink(), context);
405: writer.endElement("td"); //NOI18N
406: }
407:
408: // Get sort button.
409: UIComponent child = null;
410: if (component.getSortLevel() > 0) {
411: child = component.getToggleSortButton();
412: } else if (component.getSortCount() > 0) {
413: // Render add button when any sort has been applied.
414: child = component.getAddSortButton();
415: } else {
416: // Render primary sort button when no sorting has been applied.
417: child = component.getPrimarySortButton();
418: }
419:
420: // Render sort button.
421: writer.writeText("\n", null); //NOI18N
422: writer.startElement("td", component); //NOI18N
423: RenderingUtilities.renderComponent(child, context);
424: writer.endElement("td"); //NOI18N
425: writer.endElement("tr"); //NOI18N
426: writer.endElement("table"); //NOI18N
427: }
428: }
429:
430: /**
431: * Render group header for TableHeader components.
432: *
433: * @param context FacesContext for the current request.
434: * @param component TableHeader to be rendered.
435: * @param writer ResponseWriter to which the component should be rendered.
436: *
437: * @exception IOException if an input/output error occurs.
438: */
439: protected void renderGroupHeader(FacesContext context,
440: TableHeader component, ResponseWriter writer)
441: throws IOException {
442: if (component == null) {
443: log("renderGroupHeader", //NOI18N
444: "Cannot render group header, TableHeader is null"); //NOI18N
445: return;
446: }
447:
448: TableRowGroup group = component.getTableRowGroupAncestor();
449: if (group == null) {
450: log("renderGroupHeader", //NOI18N
451: "Cannot render group header, TableRowGroup is null"); //NOI18N
452: return;
453: }
454:
455: // Header facet should override header text.
456: UIComponent facet = group.getFacet(TableRowGroup.HEADER_FACET);
457: boolean renderHeader = facet != null && facet.isRendered();
458: boolean renderText = group.getHeaderText() != null
459: && !renderHeader;
460:
461: // Don't render controls for an empty group.
462: boolean renderTableRowGroupControls = !isEmptyGroup(component)
463: && (group != null
464: && group.isSelectMultipleToggleButton() || group
465: .isGroupToggleButton());
466:
467: if (renderText || renderTableRowGroupControls) {
468: // Render alignment span.
469: Theme theme = getTheme();
470: writer.writeText("\n", null); //NOI18N
471: writer.startElement("span", component); //NOI18N
472: writer
473: .writeAttribute(
474: "class", //NOI18N
475: theme
476: .getStyleClass(ThemeStyles.TABLE_GROUP_HEADER_LEFT),
477: null);
478:
479: // Render table row group controls.
480: if (renderTableRowGroupControls) {
481: // Render select multiple toggle button.
482: if (group.isSelectMultipleToggleButton()) {
483: writer.writeText("\n", null); //NOI18N
484: RenderingUtilities.renderComponent(component
485: .getSelectMultipleToggleButton(), context);
486: }
487:
488: // Do not render warning icon unless selectId is used.
489: if (getSelectId(component) != null) {
490: writer.writeText("\n", null); //NOI18N
491: writer.startElement("span", component); //NOI18N
492: writer
493: .writeAttribute(
494: "class", //NOI18N
495: theme
496: .getStyleClass(ThemeStyles.TABLE_GROUP_HEADER_IMAGE),
497: null);
498: writer.writeText("\n", null); //NOI18N
499: RenderingUtilities.renderComponent(component
500: .getWarningIcon(), context);
501: writer.endElement("span"); //NOI18N
502: }
503:
504: // Render group toggle button.
505: if (group.isGroupToggleButton()) {
506: writer.writeText("\n", null); //NOI18N
507: RenderingUtilities.renderComponent(component
508: .getGroupPanelToggleButton(), context);
509:
510: // Render hidden field for collapsed property.
511: RenderingUtilities.renderComponent(component
512: .getCollapsedHiddenField(), context);
513: }
514:
515: // Add space between controls and facet text.
516: if (!renderText) {
517: writer.write(" "); //NOI18N
518: }
519: }
520:
521: // Render text.
522: if (renderText) {
523: writer.writeText("\n", null); //NOI18N
524: writer.startElement("span", component); //NOI18N
525: writer
526: .writeAttribute(
527: "class", //NOI18N
528: theme
529: .getStyleClass(ThemeStyles.TABLE_GROUP_HEADER_TEXT),
530: null);
531: writer.writeText(group.getHeaderText(), null);
532: writer.endElement("span"); //NOI18N
533: }
534: writer.endElement("span"); //NOI18N
535: } else {
536: log("renderGroupHeader", //NOI18N
537: "Group controls not rendered, empty group found"); //NOI18N
538: }
539:
540: // Render facet.
541: if (renderHeader) {
542: RenderingUtilities.renderComponent(facet, context);
543: }
544: }
545:
546: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
547: // Enclosing tag methods
548: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
549:
550: /**
551: * Render enclosing tag for TableHeader components.
552: *
553: * @param context FacesContext for the current request.
554: * @param component TableHeader to be rendered.
555: * @param writer ResponseWriter to which the component should be rendered.
556: *
557: * @exception IOException if an input/output error occurs.
558: */
559: protected void renderEnclosingTagStart(FacesContext context,
560: TableHeader component, ResponseWriter writer)
561: throws IOException {
562: if (component == null) {
563: log("renderEnclosingTagStart", //NOI18N
564: "Cannot render enclosing tag, TableHeader is null"); //NOI18N
565: return;
566: }
567:
568: writer.writeText("\n", null); //NOI18N
569: writer.startElement("th", component); //NOI18N
570: writer.writeAttribute("id", component.getClientId(context),
571: null); //NOI18N
572:
573: // Render style class.
574: String extraHtml = RenderingUtilities.renderStyleClass(context,
575: writer, component, getStyleClass(component), component
576: .getExtraHtml());
577:
578: // Render colspan.
579: if (component.getColSpan() > -1
580: && (extraHtml == null || extraHtml.indexOf("colspan=") == -1)) { //NOI18N
581: writer.writeAttribute("colspan", //NOI18N
582: Integer.toString(component.getColSpan()), null); //NOI18N
583: }
584:
585: // Render rowspan.
586: if (component.getRowSpan() > -1
587: && (extraHtml == null || extraHtml.indexOf("rowspan=") == -1)) { //NOI18N
588: writer.writeAttribute("rowspan", //NOI18N
589: Integer.toString(component.getRowSpan()), null); //NOI18N
590: }
591:
592: // Render nowrap.
593: if (component.isNoWrap()
594: && (extraHtml == null || extraHtml.indexOf("nowrap=") == -1)) { //NOI18N
595: writer.writeAttribute("nowrap", "nowrap", null); //NOI18N
596: }
597:
598: // Render tooltip.
599: if (component.getToolTip() != null
600: && (extraHtml == null || extraHtml.indexOf("title=") == -1)) { //NOI18N
601: writer.writeAttribute("title", component.getToolTip(),
602: "toolTip"); //NOI18N
603: }
604:
605: // Render pass through attributes.
606: RenderingUtilities.writeStringAttributes(component, writer,
607: stringAttributes, extraHtml);
608: }
609:
610: /**
611: * Render enclosing tag for TableHeader components.
612: *
613: * @param context FacesContext for the current request.
614: * @param component TableHeader to be rendered.
615: * @param writer ResponseWriter to which the component should be rendered.
616: *
617: * @exception IOException if an input/output error occurs.
618: */
619: protected void renderEnclosingTagEnd(FacesContext context,
620: TableHeader component, ResponseWriter writer)
621: throws IOException {
622: if (component == null) {
623: log("renderEnclosingTagEnd", //NOI18N
624: "Cannot render enclosing tag, TableHeader is null"); //NOI18N
625: return;
626: }
627: writer.endElement("th"); //NOI18N
628: }
629:
630: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
631: // Private methods
632: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
633:
634: /**
635: * Helper method to get the selectId from TableRowGroup components.
636: *
637: * @param component The TableHeader component to be rendered.
638: * @return The first selectId property found.
639: */
640: private String getSelectId(TableHeader component) {
641: String selectId = null;
642: TableRowGroup group = (component != null) ? component
643: .getTableRowGroupAncestor() : null;
644: if (group == null) {
645: log("getSelectId", //NOI18N
646: "Cannot obtain select Id, TableRowGroup is null"); //NOI18N
647: return selectId;
648: }
649:
650: Iterator kids = group.getTableColumnChildren();
651: while (kids.hasNext()) {
652: TableColumn col = (TableColumn) kids.next();
653: if (!col.isRendered()) {
654: continue;
655: }
656: selectId = getSelectId(col);
657: if (selectId != null) {
658: break;
659: }
660: }
661: return selectId;
662: }
663:
664: /**
665: * Get the selectId from nested TableColumn components.
666: *
667: * @param component TableColumn to be rendered.
668: * @return The first selectId property found.
669: */
670: private String getSelectId(TableColumn component) {
671: if (component == null) {
672: log("getSelectId", //NOI18N
673: "Cannot obtain select Id, TableColumn is null"); //NOI18N
674: return null;
675: }
676:
677: // Render nested TableColumn children.
678: Iterator kids = component.getTableColumnChildren();
679: if (kids.hasNext()) {
680: while (kids.hasNext()) {
681: TableColumn col = (TableColumn) kids.next();
682: if (!col.isRendered()) {
683: continue;
684: }
685: String selectId = getSelectId(col);
686: if (selectId != null) {
687: return selectId;
688: }
689: }
690: }
691: return component.getSelectId();
692: }
693:
694: /**
695: * Helper method to get style class for TableHeader components.
696: *
697: * @param component TableHeader to be rendered.
698: * @return The style class.
699: */
700: private String getStyleClass(TableHeader component) {
701: String styleClass = null;
702: if (component == null) {
703: log("getStyleClass", //NOI18N
704: "Cannot obtain style class, TableHeader is null"); //NOI18N
705: return styleClass;
706: }
707:
708: // Get style class.
709: if (component.isGroupHeader()) {
710: styleClass = ThemeStyles.TABLE_GROUP_HEADER;
711: } else {
712: TableColumn col = component.getTableColumnAncestor();
713: if (col != null && col.isSpacerColumn()) {
714: styleClass = ThemeStyles.TABLE_TD_SPACER;
715: } else {
716: // Test for nested column headers.
717: TableColumn parent = (col != null) ? col
718: .getTableColumnAncestor() : null;
719: Iterator kids = (col != null) ? col
720: .getTableColumnChildren() : null;
721: if (kids != null && kids.hasNext()) {
722: // If TableColumn has kids, then it is a root node.
723: styleClass = ThemeStyles.TABLE_MULTIPLE_HEADER_ROOT;
724: } else if (component.getSortLevel() == 1) {
725: if (parent != null) {
726: // If TableColumn has a parent, then it is a leaf node.
727: styleClass = ThemeStyles.TABLE_MULTIPLE_HEADER_SORT;
728: } else if (component.isSelectHeader()) {
729: styleClass = ThemeStyles.TABLE_HEADER_SELECTCOL_SORT;
730: } else {
731: styleClass = ThemeStyles.TABLE_HEADER_SORT;
732: }
733: } else {
734: if (parent != null) {
735: // If TableColumn has a parent, then it is a leaf node.
736: styleClass = ThemeStyles.TABLE_MULTIPLE_HEADER;
737: } else if (component.isSelectHeader()) {
738: styleClass = ThemeStyles.TABLE_HEADER_SELECTCOL;
739: } else {
740: styleClass = ThemeStyles.TABLE_HEADER;
741: }
742: }
743: }
744: }
745: return getTheme().getStyleClass(styleClass);
746: }
747:
748: /** Helper method to get Theme objects. */
749: private Theme getTheme() {
750: return ThemeUtilities.getTheme(FacesContext
751: .getCurrentInstance());
752: }
753:
754: /**
755: * Helper method to determine if group is empty.
756: *
757: * @return true if empty, else false.
758: */
759: private boolean isEmptyGroup(TableHeader component) {
760: boolean result = false;
761: if (component == null) {
762: log("isEmptyGroup", //NOI18N
763: "Cannot determine if group is empty, TableHeader is null"); //NOI18N
764: return result;
765: }
766:
767: TableRowGroup group = component.getTableRowGroupAncestor();
768: if (group != null) {
769: result = (group.getRowCount() == 0);
770: } else {
771: log("isEmptyGroup", //NOI18N
772: "Cannot determine if group is empty, TableRowGroup is null"); //NOI18N
773: }
774: return result;
775: }
776:
777: /**
778: * Log fine messages.
779: */
780: private void log(String method, String message) {
781: // Get class.
782: Class clazz = this .getClass();
783: if (LogUtil.fineEnabled(clazz)) {
784: // Log method name and message.
785: LogUtil.fine(clazz, clazz.getName() + "." + method + ": "
786: + message); //NOI18N
787: }
788: }
789: }
|