001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/msgcntr/trunk/messageforums-app/src/java/org/sakaiproject/tool/messageforums/jsf/HierPvtMsgDataTableRender.java $
003: * $Id: HierPvtMsgDataTableRender.java 9227 2006-05-15 15:02:42Z cwen@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.tool.messageforums.jsf;
021:
022: import com.sun.faces.util.Util;
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: import javax.faces.component.UIColumn;
027: import javax.faces.component.UIComponent;
028: import javax.faces.component.UIData;
029: import javax.faces.context.FacesContext;
030: import javax.faces.context.ResponseWriter;
031: import javax.faces.el.ValueBinding;
032:
033: import com.sun.faces.renderkit.html_basic.HtmlBasicRenderer;
034:
035: import java.io.IOException;
036: import java.util.ArrayList;
037: import java.util.Iterator;
038: import java.util.List;
039:
040: import org.sakaiproject.api.app.messageforums.Message;
041: import org.sakaiproject.api.app.messageforums.MessageForumsMessageManager;
042: import org.sakaiproject.tool.messageforums.ui.PrivateMessageDecoratedBean;
043: import org.sakaiproject.component.cover.ComponentManager;
044:
045: /**
046: * @author cwen
047: *
048: * TODO To change the template for this generated type comment go to Window -
049: * Preferences - Java - Code Style - Code Templates
050: */
051: public class HierPvtMsgDataTableRender extends HtmlBasicRenderer {
052: protected static Log log = LogFactory
053: .getLog(HierPvtMsgDataTableRender.class);
054:
055: private static final String RESOURCE_PATH;
056:
057: private static final String BARIMG;
058:
059: private static final String CURSOR;
060:
061: static {
062: RESOURCE_PATH = "/" + "sakai-messageforums-tool";
063: BARIMG = RESOURCE_PATH + "/" + "images/collapse.gif";
064: CURSOR = "cursor:pointer";
065: }
066:
067: public boolean getRendersChildren() {
068: return true;
069: }
070:
071: public void encodeBegin(FacesContext context, UIComponent component)
072: throws IOException {
073:
074: if ((context == null) || (component == null)) {
075: throw new NullPointerException(
076: Util
077: .getExceptionMessageString(Util.NULL_PARAMETERS_ERROR_MESSAGE_ID));
078: }
079: if (log.isTraceEnabled()) {
080: log.trace("Begin encoding component " + component.getId());
081: }
082:
083: // suppress rendering if "rendered" property on the component is
084: // false.
085: if (!component.isRendered()) {
086: if (log.isTraceEnabled()) {
087: log.trace("No encoding necessary " + component.getId()
088: + " since "
089: + "rendered attribute is set to false ");
090: }
091: return;
092: }
093: UIData data = (UIData) component;
094: data.setRowIndex(-1);
095:
096: // Render the beginning of the table
097: ResponseWriter writer = context.getResponseWriter();
098: writer.startElement("table", data);
099: writeIdAttributeIfNecessary(context, writer, component);
100: String styleClass = (String) data.getAttributes().get(
101: "styleClass");
102: if (styleClass != null) {
103: writer.writeAttribute("class", styleClass, "styleClass");
104: }
105: Util.renderPassThruAttributes(writer, component,
106: new String[] { "rows" });
107: writer.writeText("\n", null);
108:
109: // Render the header facets (if any)
110: UIComponent header = getFacet(data, "header");
111: int headerFacets = getFacetCount(data, "header");
112: String headerClass = (String) data.getAttributes().get(
113: "headerClass");
114: if ((header != null) || (headerFacets > 0)) {
115: writer.startElement("thead", data);
116: writer.writeText("\n", null);
117: }
118: if (header != null) {
119: writer.startElement("tr", header);
120: writer.startElement("th", header);
121: if (headerClass != null) {
122: writer.writeAttribute("class", headerClass,
123: "headerClass");
124: }
125: writer.writeAttribute("colspan", "" + getColumnCount(data),
126: null);
127: writer.writeAttribute("scope", "colgroup", null);
128: encodeRecursive(context, header);
129: writer.endElement("th");
130: writer.endElement("tr");
131: writer.writeText("\n", null);
132: }
133: if (headerFacets > 0) {
134: writer.startElement("tr", data);
135: writer.writeText("\n", null);
136: Iterator columns = getColumns(data);
137: while (columns.hasNext()) {
138: UIColumn column = (UIColumn) columns.next();
139: writer.startElement("th", column);
140: if (headerClass != null) {
141: writer.writeAttribute("class", headerClass,
142: "headerClass");
143: }
144: writer.writeAttribute("scope", "col", null);
145: UIComponent facet = getFacet(column, "header");
146: if (facet != null) {
147: encodeRecursive(context, facet);
148: }
149: writer.endElement("th");
150: writer.writeText("\n", null);
151: }
152: writer.endElement("tr");
153: writer.writeText("\n", null);
154: }
155: if ((header != null) || (headerFacets > 0)) {
156: writer.endElement("thead");
157: writer.writeText("\n", null);
158: }
159:
160: // Render the footer facets (if any)
161: UIComponent footer = getFacet(data, "footer");
162: int footerFacets = getFacetCount(data, "footer");
163: String footerClass = (String) data.getAttributes().get(
164: "footerClass");
165: if ((footer != null) || (footerFacets > 0)) {
166: writer.startElement("tfoot", data);
167: writer.writeText("\n", null);
168: }
169: if (footer != null) {
170: writer.startElement("tr", footer);
171: writer.startElement("td", footer);
172: if (footerClass != null) {
173: writer.writeAttribute("class", footerClass,
174: "footerClass");
175: }
176: writer.writeAttribute("colspan", "" + getColumnCount(data),
177: null);
178: encodeRecursive(context, footer);
179: writer.endElement("td");
180: writer.endElement("tr");
181: writer.writeText("\n", null);
182: }
183: if (footerFacets > 0) {
184: writer.startElement("tr", data);
185: writer.writeText("\n", null);
186: Iterator columns = getColumns(data);
187: while (columns.hasNext()) {
188: UIColumn column = (UIColumn) columns.next();
189: writer.startElement("td", column);
190: if (footerClass != null) {
191: writer.writeAttribute("class", footerClass,
192: "footerClass");
193: }
194: UIComponent facet = getFacet(column, "footer");
195: if (facet != null) {
196: encodeRecursive(context, facet);
197: }
198: writer.endElement("td");
199: writer.writeText("\n", null);
200: }
201: writer.endElement("tr");
202: writer.writeText("\n", null);
203: }
204: if ((footer != null) || (footerFacets > 0)) {
205: writer.endElement("tfoot");
206: writer.writeText("\n", null);
207: }
208:
209: }
210:
211: public void encodeChildren(FacesContext context,
212: UIComponent component) throws IOException {
213: MessageForumsMessageManager messageManager = (MessageForumsMessageManager) ComponentManager
214: .get("org.sakaiproject.api.app.messageforums.MessageForumsMessageManager");
215:
216: if ((context == null) || (component == null)) {
217: throw new NullPointerException(
218: Util
219: .getExceptionMessageString(Util.NULL_PARAMETERS_ERROR_MESSAGE_ID));
220: }
221: if (log.isTraceEnabled()) {
222: log.trace("Begin encoding children " + component.getId());
223: }
224: if (!component.isRendered()) {
225: if (log.isTraceEnabled()) {
226: log.trace("No encoding necessary " + component.getId()
227: + " since "
228: + "rendered attribute is set to false ");
229: }
230: return;
231: }
232: UIData data = (UIData) component;
233:
234: ValueBinding msgsBinding = component.getValueBinding("value");
235: List msgBeanList = (List) msgsBinding.getValue(context);
236:
237: // Set up variables we will need
238: String columnClasses[] = getColumnClasses(data);
239: int columnStyle = 0;
240: int columnStyles = columnClasses.length;
241: String rowClasses[] = getRowClasses(data);
242: int rowStyles = rowClasses.length;
243: ResponseWriter writer = context.getResponseWriter();
244: Iterator kids = null;
245: Iterator grandkids = null;
246:
247: // Iterate over the rows of data that are provided
248: int processed = 0;
249: int rowIndex = data.getFirst() - 1;
250: int rows = data.getRows();
251: int rowStyle = 0;
252:
253: writer.startElement("tbody", component);
254: writer.writeText("\n", null);
255: int hideDivNo = 0;
256: while (true) {
257: // PrivateMessageDecoratedBean dmb = null;
258: // if(msgBeanList !=null && msgBeanList.size()>(rowIndex+1) &&
259: // rowIndex>=-1)
260: // {
261: // dmb = (PrivateMessageDecoratedBean)msgBeanList.get(rowIndex+1);
262: // }
263: // boolean hasChildBoolean = false;
264: // if(dmb != null)
265: // {
266: // for(int i=0; i<msgBeanList.size(); i++)
267: // {
268: // PrivateMessageDecoratedBean tempDmb =
269: // (PrivateMessageDecoratedBean)msgBeanList.get(i);
270: // if(tempDmb.getUiInReply() != null &&
271: // tempDmb.getUiInReply().getId().equals(dmb.getMsg().getId()))
272: // {
273: // hasChildBoolean = true;
274: // break;
275: // }
276: // }
277: // }
278: // Have we displayed the requested number of rows?
279: if ((rows > 0) && (++processed > rows)) {
280: break;
281: }
282: // Select the current row
283: data.setRowIndex(++rowIndex);
284: if (!data.isRowAvailable()) {
285: break; // Scrolled past the last row
286: }
287:
288: PrivateMessageDecoratedBean dmb = null;
289: dmb = (PrivateMessageDecoratedBean) data.getRowData();
290: boolean hasChildBoolean = false;
291: if (dmb != null) {
292: // if dmb has depth = 0, check for children
293: if (dmb.getDepth() == 0) {
294: // first, get the index of the dmb
295: int index = -1;
296:
297: for (int i = 0; i < msgBeanList.size(); i++) {
298: PrivateMessageDecoratedBean tempDmb = (PrivateMessageDecoratedBean) msgBeanList
299: .get(i);
300: if (dmb.getMsg().getId().equals(
301: tempDmb.getMsg().getId())) {
302: index = i;
303: break;
304: }
305: }
306: if (index < (msgBeanList.size() - 1) && index >= 0) {
307: PrivateMessageDecoratedBean nextDmb = (PrivateMessageDecoratedBean) msgBeanList
308: .get(index + 1);
309:
310: if (nextDmb.getDepth() > 0) {
311: hasChildBoolean = true;
312: }
313: }
314: }
315: }
316:
317: if (dmb.getDepth() > 0) {
318: writer.write("<tr style=\"display:none\" id=\"_id_"
319: + new Integer(hideDivNo).toString()
320: + "__hide_division_" + "\">");
321: } else {
322: writer.write("<tr>");
323: }
324:
325: if (rowStyles > 0) {
326: writer.writeAttribute("class", rowClasses[rowStyle++],
327: "rowClasses");
328: if (rowStyle >= rowStyles) {
329: rowStyle = 0;
330: }
331: }
332: writer.writeText("\n", null);
333:
334: // Iterate over the child UIColumn components for each row
335: columnStyle = 0;
336: kids = getColumns(data);
337: while (kids.hasNext()) {
338:
339: // Identify the next renderable column
340: UIColumn column = (UIColumn) kids.next();
341:
342: // Render the beginning of this cell
343: writer.startElement("td", column);
344: if (columnStyles > 0) {
345: writer.writeAttribute("class",
346: columnClasses[columnStyle++],
347: "columnClasses");
348: if (columnStyle >= columnStyles) {
349: columnStyle = 0;
350: }
351: }
352:
353: if (dmb != null && dmb.getDepth() > 0) {
354: if (column.getId().endsWith("_msg_subject")) {
355: String indent = "";
356: int indentInt = dmb.getDepth() * 4;
357: for (int i = 0; i < indentInt; i++) {
358: indent += " ";
359: }
360: writer.write(indent);
361: }
362: } else {
363: if (column.getId().endsWith("_msg_subject")) {
364: if (hasChildBoolean && dmb.getDepth() == 0) {
365: writer.write(" <img src=\"" + BARIMG
366: + "\" style=\"" + CURSOR
367: + "\" id=\"_id_"
368: + new Integer(hideDivNo).toString()
369: + "__img_hide_division_\""
370: + " onclick=\"");
371: int childNo = getTotalChildNo(dmb,
372: msgBeanList);
373: String hideTr = "";
374: for (int i = 0; i < childNo; i++) {
375: hideTr += "javascript:showHideDiv('_id_"
376: + new Integer(hideDivNo + i)
377: .toString()
378: + "', '"
379: + RESOURCE_PATH + "');";
380: }
381: writer.write(hideTr);
382: writer.write("\" />");
383: }
384: }
385: }
386: // Render the contents of this cell by iterating over
387: // the kids of our kids
388: grandkids = getChildren(column);
389: while (grandkids.hasNext()) {
390: encodeRecursive(context, (UIComponent) grandkids
391: .next());
392: }
393:
394: // Render the ending of this cell
395: writer.endElement("td");
396: writer.writeText("\n", null);
397:
398: }
399:
400: // Render the ending of this row
401: writer.endElement("tr");
402: writer.writeText("\n", null);
403: if (dmb != null && dmb.getDepth() > 0) {
404: ////
405: /*ValueBinding expandedBinding =
406: component.getValueBinding("expanded");
407: String expanded = "";
408: if(expandedBinding != null)
409: expanded = (String)expandedBinding.getValue(context);
410:
411: if(expanded.equalsIgnoreCase("true"))
412: {*/
413: writer.write("<script type=\"text/javascript\">");
414: writer.write(" showHideDiv('_id_"
415: + new Integer(hideDivNo).toString() + "', '"
416: + RESOURCE_PATH + "');");
417: writer.write("</script>");
418: ////// }
419:
420: hideDivNo++;
421: }
422: }
423: writer.endElement("tbody");
424: writer.writeText("\n", null);
425:
426: // Clean up after ourselves
427: data.setRowIndex(-1);
428: if (log.isTraceEnabled()) {
429: log.trace("End encoding children " + component.getId());
430: }
431: }
432:
433: public void encodeEnd(FacesContext context, UIComponent component)
434: throws IOException {
435:
436: if ((context == null) || (component == null)) {
437: throw new NullPointerException(
438: Util
439: .getExceptionMessageString(Util.NULL_PARAMETERS_ERROR_MESSAGE_ID));
440: }
441: if (!component.isRendered()) {
442: if (log.isTraceEnabled()) {
443: log.trace("No encoding necessary " + component.getId()
444: + " since "
445: + "rendered attribute is set to false ");
446: }
447: return;
448: }
449: UIData data = (UIData) component;
450: data.setRowIndex(-1);
451: ResponseWriter writer = context.getResponseWriter();
452:
453: // Render the ending of this table
454: writer.endElement("table");
455: writer.writeText("\n", null);
456: if (log.isTraceEnabled()) {
457: log.trace("End encoding component " + component.getId());
458: }
459:
460: }
461:
462: private int getTotalChildNo(PrivateMessageDecoratedBean dmb,
463: List beanList) {
464: MessageForumsMessageManager messageManager = (MessageForumsMessageManager) ComponentManager
465: .get("org.sakaiproject.api.app.messageforums.MessageForumsMessageManager");
466: List allChild = new ArrayList();
467: messageManager.getChildMsgs(dmb.getMsg().getId(), allChild);
468: int no = 0;
469:
470: for (int i = 0; i < beanList.size(); i++) {
471: PrivateMessageDecoratedBean this Bean = (PrivateMessageDecoratedBean) beanList
472: .get(i);
473: for (int j = 0; j < allChild.size(); j++) {
474: Message child = (Message) allChild.get(j);
475: if (this Bean.getMsg().getId().equals(child.getId())) {
476: no++;
477: break;
478: }
479: }
480: }
481: return no;
482: }
483:
484: // --------------------------------------------------------- Private Methods
485:
486: /**
487: * <p>
488: * Return an array of stylesheet classes to be applied to each column in the
489: * table in the order specified. Every column may or may not have a
490: * stylesheet.
491: * </p>
492: *
493: * @param data
494: * {@link UIData}component being rendered
495: */
496: private String[] getColumnClasses(UIData data) {
497:
498: String values = (String) data.getAttributes().get(
499: "columnClasses");
500: if (values == null) {
501: return (new String[0]);
502: }
503: values = values.trim();
504: ArrayList list = new ArrayList();
505: while (values.length() > 0) {
506: int comma = values.indexOf(",");
507: if (comma >= 0) {
508: list.add(values.substring(0, comma).trim());
509: values = values.substring(comma + 1);
510: } else {
511: list.add(values.trim());
512: values = "";
513: }
514: }
515: String results[] = new String[list.size()];
516: return ((String[]) list.toArray(results));
517:
518: }
519:
520: /**
521: * <p>
522: * Return the number of child <code>UIColumn</code> components that are
523: * nested in the specified {@link UIData}.
524: * </p>
525: *
526: * @param data
527: * {@link UIData}component being analyzed
528: */
529: private int getColumnCount(UIData data) {
530:
531: int columns = 0;
532: Iterator kids = getColumns(data);
533: while (kids.hasNext()) {
534: UIComponent kid = (UIComponent) kids.next();
535: columns++;
536: }
537: return (columns);
538:
539: }
540:
541: /**
542: * <p>
543: * Return an Iterator over the <code>UIColumn</code> children of the
544: * specified <code>UIData</code> that have a <code>rendered</code>
545: * property of <code>true</code>.
546: * </p>
547: *
548: * @param data
549: * <code>UIData</code> for which to extract children
550: */
551: private Iterator getColumns(UIData data) {
552:
553: List results = new ArrayList();
554: Iterator kids = data.getChildren().iterator();
555: while (kids.hasNext()) {
556: UIComponent kid = (UIComponent) kids.next();
557: if ((kid instanceof UIColumn) && kid.isRendered()) {
558: results.add(kid);
559: }
560: }
561: return (results.iterator());
562:
563: }
564:
565: /**
566: * <p>
567: * Return the number of child <code>UIColumn</code> components nested in
568: * the specified <code>UIData</code> that have a facet with the specified
569: * name.
570: * </p>
571: *
572: * @param data
573: * <code>UIData</code> component being analyzed
574: * @param name
575: * Name of the facet being analyzed
576: */
577: private int getFacetCount(UIData data, String name) {
578:
579: int n = 0;
580: Iterator kids = getColumns(data);
581: while (kids.hasNext()) {
582: UIComponent kid = (UIComponent) kids.next();
583: if (getFacet(kid, name) != null) {
584: n++;
585: }
586: }
587: return (n);
588:
589: }
590:
591: /**
592: * <p>
593: * Return an array of stylesheet classes to be applied to each row in the
594: * table, in the order specified. Every row may or may not have a
595: * stylesheet.
596: * </p>
597: *
598: * @param data
599: * {@link UIData}component being rendered
600: */
601: private String[] getRowClasses(UIData data) {
602:
603: String values = (String) data.getAttributes().get("rowClasses");
604: if (values == null) {
605: return (new String[0]);
606: }
607: values = values.trim();
608: ArrayList list = new ArrayList();
609: while (values.length() > 0) {
610: int comma = values.indexOf(",");
611: if (comma >= 0) {
612: list.add(values.substring(0, comma).trim());
613: values = values.substring(comma + 1);
614: } else {
615: list.add(values.trim());
616: values = "";
617: }
618: }
619: String results[] = new String[list.size()];
620: return ((String[]) list.toArray(results));
621:
622: }
623:
624: private void renderThread(ResponseWriter writer, UIData data,
625: int rows, Integer processed, int rowIndex, int rowStyles,
626: int rowStyle, int columnStyle, int columnStyles,
627: String columnClasses[], String rowClasses[],
628: FacesContext context, List msgs, Message currentMsg) {
629: Iterator kids = null;
630: Iterator grandkids = null;
631:
632: for (int i = 0; i < msgs.size(); i++) {
633: Message this Msg = (Message) msgs.get(i);
634: if (this Msg.getId().equals(currentMsg.getId())) {
635: msgs.remove(i);
636: break;
637: }
638: }
639:
640: try {
641: int processedInt = processed.intValue();
642: if ((rows > 0) && (++processedInt > rows)) {
643: processed = new Integer(processedInt);
644: return;
645: }
646: data.setRowIndex(++rowIndex);
647: if (!data.isRowAvailable()) {
648: return;
649: }
650:
651: writer.startElement("tr", data);
652: if (rowStyles > 0) {
653: writer.writeAttribute("class", rowClasses[rowStyle++],
654: "rowClasses");
655: if (rowStyle >= rowStyles) {
656: rowStyle = 0;
657: }
658: }
659: writer.writeText("\n", null);
660:
661: columnStyle = 0;
662: kids = getColumns(data);
663: while (kids.hasNext()) {
664: UIColumn column = (UIColumn) kids.next();
665:
666: writer.startElement("td", column);
667: if (columnStyles > 0) {
668: writer.writeAttribute("class",
669: columnClasses[columnStyle++],
670: "columnClasses");
671: if (columnStyle >= columnStyles) {
672: columnStyle = 0;
673: }
674: }
675:
676: grandkids = getChildren(column);
677: while (grandkids.hasNext()) {
678: encodeRecursive(context, (UIComponent) grandkids
679: .next());
680: }
681:
682: writer.endElement("td");
683: writer.writeText("\n", null);
684:
685: }
686:
687: writer.endElement("tr");
688: writer.writeText("\n", null);
689: } catch (Exception e) {
690: e.printStackTrace();
691: }
692:
693: MessageForumsMessageManager messageManager = (MessageForumsMessageManager) ComponentManager
694: .get("org.sakaiproject.api.app.messageforums.MessageForumsMessageManager");
695: List replyMsgs = messageManager
696: .getFirstLevelChildMsgs(currentMsg.getId());
697: if (replyMsgs != null) {
698: for (int i = 0; i < replyMsgs.size(); i++) {
699: Message childM = (Message) replyMsgs.get(i);
700: for (int j = 0; j < msgs.size(); j++) {
701: Message remainMsg = (Message) msgs.get(j);
702: if (childM.getId().equals(remainMsg.getId())) {
703: renderThread(writer, data, rows, processed,
704: rowIndex, rowStyles, rowStyle,
705: columnStyle, columnStyles,
706: columnClasses, rowClasses, context,
707: msgs, remainMsg);
708: }
709: }
710: }
711: }
712: }
713: }
|