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 java.io.IOException;
044: import java.util.Iterator;
045: import java.util.Map;
046: import javax.faces.FacesException;
047: import javax.faces.component.EditableValueHolder;
048: import javax.faces.component.NamingContainer;
049: import javax.faces.component.UIComponent;
050: import javax.faces.context.FacesContext;
051: import javax.faces.context.ResponseWriter;
052: import com.sun.rave.web.ui.component.AddRemove;
053: import com.sun.rave.web.ui.component.Label;
054: import com.sun.rave.web.ui.component.ListSelector;
055: import com.sun.rave.web.ui.component.StaticText;
056: import com.sun.rave.web.ui.theme.Theme;
057: import com.sun.rave.web.ui.theme.ThemeJavascript;
058: import com.sun.rave.web.ui.theme.ThemeStyles;
059: import com.sun.rave.web.ui.util.RenderingUtilities;
060: import com.sun.rave.web.ui.util.ThemeUtilities;
061:
062: /**
063: * <p>Renderer for a {@link com.sun.rave.web.ui.component.AddRemove} component.</p>
064: */
065:
066: public class AddRemoveRenderer extends ListRendererBase {
067:
068: private final static boolean DEBUG = false;
069: private final static String SELECTED_ID = "_selected"; //NOI18N
070: private final static String AVAILABLE_ID = "_available"; //NOI18N
071: private final static String ITEMS_ID = "_item_list"; //NOI18N
072:
073: /**
074: * <p>Render the list.
075: *
076: * @param context <code>FacesContext</code> for the current request
077: * @param component <code>UIComponent</code> to be rendered
078: * end should be rendered
079: *
080: * @exception IOException if an input/output error occurs
081: */
082: public void encodeEnd(FacesContext context, UIComponent component)
083: throws IOException {
084:
085: if (DEBUG)
086: log("encodeEnd()");
087:
088: if (component instanceof AddRemove) {
089: renderListComponent((AddRemove) component, context,
090: getStyles(context));
091: } else {
092: String message = "Component " + component.toString() + //NOI18N
093: " has been associated with a ListboxRenderer. " + //NOI18N
094: " This renderer can only be used by components " + //NOI18N
095: " that extend com.sun.rave.web.ui.component.Selector."; //NOI18N
096: throw new FacesException(message);
097: }
098: }
099:
100: /**
101: * <p>This method determines whether the component should be
102: * rendered as a standalone list, or laid out together with a
103: * label that was defined as part of the component.</p>
104: *
105: * <p>A label will be rendered if either of the following is
106: * true:</p>
107: * <ul>
108: * <li>The page author defined a label facet; or</li>
109: * <li>The page author specified text in the label attribute.</li>
110: * </ul>
111: * <p>If there is a label, the component will be laid out using a
112: * HTML table. If not, the component will be rendered as a
113: * standalone HTML <tt>select</tt> element.</p>
114: * @param component The component associated with the
115: * renderer. Must be a subclass of ListSelector.
116: * @param context The FacesContext of the request
117: * @param styles A String array of styles used to render the
118: * component. The first item of the array is the name of the
119: * JavaScript method that handles change event. The second item is
120: * the style used when the list is enabled. The third style is the
121: * one to use when the list is disabled. The fourth item is the
122: * style to use for an item that is enabled, the fifth to use for
123: * an item that is disabled, and the sixth to use when the item is
124: * selected.
125: * @throws java.io.IOException if the renderer fails to write to
126: * the response
127: */
128: void renderListComponent(AddRemove component, FacesContext context,
129: String[] styles) throws IOException {
130:
131: if (DEBUG)
132: log("renderListComponent()");
133:
134: if (component.isReadOnly()) {
135: UIComponent label = component.getSelectedLabelComponent();
136: super .renderReadOnlyList(component, label, context,
137: styles[19]);
138: return;
139: }
140:
141: String id = component.getClientId(context);
142: String jsObject = null;
143: Object jsO = component.getAttributes().get(AddRemove.JSOBJECT);
144: if (jsO == null) {
145: jsObject = id.replace(':', '_');
146: jsObject = "AddRemove_".concat(jsObject);
147: component.getAttributes().put(AddRemove.JSOBJECT, jsObject);
148: } else {
149: jsObject = jsO.toString();
150: }
151:
152: ResponseWriter writer = context.getResponseWriter();
153:
154: // We should check if this one is already printed on the
155: // page...
156: writer.writeText("\n", null);
157: writer.startElement("script", component); // NOI18N
158: writer.writeAttribute("type", "text/javascript", null); // NOI18N
159: writer.writeURIAttribute("src", styles[16], null); // NOI18N
160: writer.endElement("script"); // NOI18N
161: writer.write("\n"); // NOI18N
162:
163: renderOpenEncloser(component, context, "div", styles[19]); //NOI18N
164:
165: if (component.isVertical()) {
166: renderVerticalAddRemove(component, context, writer, styles);
167: } else {
168: renderHorizontalAddRemove(component, context, writer,
169: styles);
170: }
171:
172: UIComponent footerComponent = component
173: .getFacet(AddRemove.FOOTER_FACET);
174: if (footerComponent != null) {
175: writer.startElement("div", component); //NOI18N
176: writer.writeText("\n", null); //NOI18N
177: RenderingUtilities
178: .renderComponent(footerComponent, context);
179: writer.writeText("\n", null); //NOI18N
180: writer.endElement("div"); //NOI18N
181: writer.writeText("\n", null); //NOI18N
182: }
183:
184: RenderingUtilities.renderHiddenField(component, writer, id
185: .concat(ITEMS_ID), component.getAllValues());
186: writer.writeText("\n", null); //NOI18N
187:
188: // Value field
189: renderHiddenValue(component, context, writer, styles[19]);
190:
191: writer.writeText("\n", null); //NOI18N
192: writer.endElement("div"); //NOI18N
193: writer.writeText("\n", null); //NOI18N
194:
195: // Initialize the JavaScript variable
196: StringBuffer jsBuffer = new StringBuffer(200);
197: jsBuffer.append("var "); //NOI18N
198: jsBuffer.append(jsObject);
199: jsBuffer.append(" = new AddRemove(\'"); //NOI18N
200: jsBuffer.append(id);
201: jsBuffer.append("\', \'"); //NOI18N
202: jsBuffer.append(component.getSeparator());
203: jsBuffer.append("\');\n"); //NOI18N
204: jsBuffer.append(jsObject);
205: jsBuffer.append(AddRemove.UPDATEBUTTONS_FUNCTION);
206:
207: if (component.isDuplicateSelections()) {
208: jsBuffer.append("\n"); //NOI18N
209: jsBuffer.append(jsObject);
210: jsBuffer.append(AddRemove.MULTIPLEADDITIONS_FUNCTION);
211: }
212:
213: writer.writeText("\n", null); //NOI18N
214: writer.startElement("script", component); // NOI18N
215: writer.writeAttribute("type", "text/javascript", null); // NOI18N
216: writer.writeText(jsBuffer.toString(), null);
217: writer.writeText("\n", null); //NOI18N
218: writer.endElement("script"); // NOI18N
219: writer.write("\n"); // NOI18N
220:
221: }
222:
223: private void renderHorizontalAddRemove(AddRemove component,
224: FacesContext context, ResponseWriter writer, String[] styles)
225: throws IOException {
226:
227: // If the label goes on top, render it first...
228:
229: UIComponent headerComponent = component.getHeaderComponent();
230: if (headerComponent != null) {
231:
232: if (!component.isLabelOnTop()) {
233: writer.writeText("\n", null); //NOI18N
234: writer.startElement("span", component);
235: writer.writeAttribute("class", styles[17], null);
236: writer.writeText("\n", null); //NOI18N
237:
238: RenderingUtilities.renderComponent(headerComponent,
239: context);
240: writer.writeText("\n", null); //NOI18N
241: writer.endElement("span"); //NOI18N
242: writer.writeText("\n", null); //NOI18N
243: } else {
244: RenderingUtilities.renderComponent(headerComponent,
245: context);
246: writer.startElement("br", component); //NOI18N
247: writer.endElement("br"); //NOI18N
248: }
249: }
250:
251: // <RAVE>
252: // Put the three columns into a table so that they can be displayed horizontally
253: // in a table cell as in portlet. See bug 6299233
254:
255: writer.writeText("\n", null); //NOI18N
256: writer.startElement("div", component); //NOI18N
257: writer.writeText("\n", null); //NOI18N
258: writer.startElement("table", component); //NOI18N
259: writer.writeText("\n", null); //NOI18N
260: writer.startElement("tr", component); //NOI18N
261: writer.writeText("\n", null); //NOI18N
262:
263: // <RAVE>
264:
265: // First column: available items
266: // <RAVE>
267: renderTableCellStart(component, writer);
268: // <RAVE>
269: renderColumnTop(component, writer, styles[17]);
270: RenderingUtilities.renderComponent(component
271: .getAvailableLabelComponent(), context);
272: renderColumnMiddle(component, writer);
273: renderAvailableList(component, context, styles);
274: renderColumnBottom(writer);
275: // <RAVE>
276: renderTableCellEnd(writer);
277: // <RAVE>
278:
279: // Second column: button row
280: // <RAVE>
281: renderTableCellStart(component, writer);
282: // <RAVE>
283: renderColumnTop(component, writer, styles[17]);
284: // We need to render a space holder with an for formatting
285: writer.startElement("span", component); //NOI18N
286: // Do not change this to "writeText", it will format the '&'!
287: writer.write(" "); //NOI18N
288: writer.endElement("span"); //NOI18N
289: renderColumnMiddle(component, writer);
290: renderButtons(component, context, writer, styles);
291: renderColumnBottom(writer);
292: // <RAVE>
293: renderTableCellEnd(writer);
294: // <RAVE>
295:
296: // Third column: selected list row
297: // <RAVE>
298: renderTableCellStart(component, writer);
299: // <RAVE>
300: renderColumnTop(component, writer, styles[17]);
301: RenderingUtilities.renderComponent(component
302: .getSelectedLabelComponent(), context);
303: renderColumnMiddle(component, writer);
304: renderSelectedList(component, context, styles);
305: renderColumnBottom(writer);
306: // <RAVE>
307: renderTableCellEnd(writer);
308: // <RAVE>
309:
310: // <RAVE>
311: // Close the table row
312: writer.endElement("tr"); //NOI18N
313: writer.writeText("\n", null); //NOI18N
314: writer.endElement("table"); //NOI18N
315: writer.writeText("\n", null); //NOI18N
316: writer.endElement("div"); //NOI18N
317: writer.writeText("\n", null); //NOI18N
318: // <RAVE>
319:
320: writer.startElement("div", component); //NOI18N
321: writer.writeAttribute("class", styles[18], null); //NOI18N
322: writer.endElement("div"); //NOI18N
323:
324: }
325:
326: // <RAVE>
327: private void renderTableCellStart(AddRemove component,
328: ResponseWriter writer) throws IOException {
329: writer.startElement("td", component); //NOI18N
330: writer.writeAttribute("align", "center", null); //NOI18N
331: writer.writeAttribute("valign", "top", null); //NOI18N
332: writer.writeText("\n", null); //NOI18N
333: }
334:
335: // <RAVE>
336:
337: // <RAVE>
338: private void renderTableCellEnd(ResponseWriter writer)
339: throws IOException {
340: writer.endElement("td"); //NOI18N
341: writer.writeText("\n", null); //NOI18N
342: }
343:
344: // <RAVE>
345:
346: private void renderVerticalAddRemove(AddRemove component,
347: FacesContext context, ResponseWriter writer, String[] styles)
348: throws IOException {
349:
350: // First column: available items
351:
352: writer.startElement("div", component); //NOI18N
353: RenderingUtilities.renderComponent(component
354: .getAvailableLabelComponent(), context);
355: writer.endElement("div");
356:
357: writer.startElement("div", component); //NOI18N
358: renderAvailableList(component, context, styles);
359: writer.endElement("div");
360:
361: writer.startElement("div", component); //NOI18N
362: renderAddButtonRow(component, context, writer, styles);
363: writer.endElement("div");
364:
365: writer.startElement("div", component); //NOI18N
366: RenderingUtilities.renderComponent(component
367: .getSelectedLabelComponent(), context);
368: writer.endElement("div");
369:
370: writer.startElement("div", component); //NOI18N
371: renderSelectedList(component, context, styles);
372: writer.endElement("div");
373:
374: if (component.isMoveButtons()) {
375: writer.startElement("div", component); //NOI18N
376: renderMoveButtonRow(component, context, writer, styles);
377: }
378: writer.endElement("div");
379: }
380:
381: private void renderColumnTop(AddRemove addRemove,
382: ResponseWriter writer, String style) throws IOException {
383:
384: // Render the available elements
385: writer.startElement("div", addRemove); //NOI18N
386: writer.writeAttribute("class", style, null); //NOI18N
387: writer.writeText("\n", null); //NOI18N
388: }
389:
390: private void renderColumnMiddle(AddRemove addRemove,
391: ResponseWriter writer) throws IOException {
392: writer.writeText("\n", null); //NOI18N
393: writer.startElement("br", addRemove); //NOI18N
394: writer.endElement("br"); //NOI18N
395: writer.writeText("\n", null); //NOI18N
396: }
397:
398: private void renderColumnBottom(ResponseWriter writer)
399: throws IOException {
400: writer.writeText("\n", null); //NOI18N
401: writer.endElement("div"); //NOI18N
402: writer.writeText("\n", null); //NOI18N
403: }
404:
405: private void renderButtons(AddRemove component,
406: FacesContext context, ResponseWriter writer, String[] styles)
407: throws IOException {
408:
409: writer.writeText("\n", null); //NOI18N
410: writer.startElement("div", component); //NOI18N
411: //writer.writeAttribute("style", styles[20], null); //NOI18N
412: writer.writeText("\n", null); //NOI18N
413: writer.startElement("table", component); //NOI18N
414: writer.writeAttribute("class", styles[10], null); //NOI18N
415: writer.writeText("\n", null); //NOI18N
416: writer.startElement("tr", component); //NOI18N
417: writer.writeText("\n", null); //NOI18N
418: writer.startElement("td", component); //NOI18N
419: writer.writeAttribute("align", "center", null); //NOI18N
420: writer.writeAttribute("width", "125px", null); //NOI18N
421: writer.writeText("\n", null); //NOI18N
422: UIComponent addButton = component
423: .getAddButtonComponent(context);
424: if (addButton.getParent() == null) {
425: addButton.setParent(component);
426: RenderingUtilities.renderComponent(addButton, context);
427: addButton.setParent(null);
428: } else {
429: RenderingUtilities.renderComponent(addButton, context);
430: }
431: writer.writeText("\n", null); //NOI18N
432:
433: if (component.isSelectAll()) {
434: renderButton(component, component
435: .getAddAllButtonComponent(), styles[14], writer,
436: context);
437: }
438: String buttonStyle = null;
439: if (component.isSelectAll()) {
440: buttonStyle = styles[15];
441: } else {
442: buttonStyle = styles[14];
443: }
444: renderButton(component, component.getRemoveButtonComponent(),
445: buttonStyle, writer, context);
446: if (component.isSelectAll()) {
447: renderButton(component, component
448: .getRemoveAllButtonComponent(), styles[14], writer,
449: context);
450: }
451:
452: if (component.isMoveButtons()) {
453: renderButton(component, component
454: .getMoveUpButtonComponent(), styles[15], writer,
455: context);
456: renderButton(component, component
457: .getMoveDownButtonComponent(), styles[14], writer,
458: context);
459: }
460:
461: writer.endElement("td"); //NOI18N
462: writer.writeText("\n", null); //NOI18N
463: writer.endElement("tr"); //NOI18N
464: writer.writeText("\n", null); //NOI18N
465: writer.endElement("table"); //NOI18N
466: writer.writeText("\n", null); //NOI18N
467: writer.endElement("div"); //NOI18N
468: writer.writeText("\n", null); //NOI18N
469: }
470:
471: private void renderAddButtonRow(AddRemove component,
472: FacesContext context, ResponseWriter writer, String[] styles)
473: throws IOException {
474:
475: writer.startElement("table", component); //NOI18N
476: writer.writeAttribute("class", styles[10], null); //NOI18N
477: writer.writeText("\n", null); //NOI18N
478: writer.startElement("tr", component); //NOI18N
479: writer.writeAttribute("valign", "top", null); //NOI18N
480: writer.writeText("\n", null); //NOI18N
481:
482: renderButtonVertical(component, component
483: .getAddButtonComponent(context), styles[11],
484: styles[20], writer, context);
485:
486: if (component.isSelectAll()) {
487: renderButtonVertical(component, component
488: .getAddAllButtonComponent(), styles[12],
489: styles[20], writer, context);
490: }
491: renderButtonVertical(component, component
492: .getRemoveButtonComponent(), styles[13], styles[20],
493: writer, context);
494:
495: if (component.isSelectAll()) {
496: renderButtonVertical(component, component
497: .getRemoveAllButtonComponent(), styles[12],
498: styles[20], writer, context);
499: }
500:
501: writer.endElement("tr"); //NOI18N
502: writer.writeText("\n", null); //NOI18N
503: writer.endElement("table"); //NOI18N
504: writer.writeText("\n", null); //NOI18N
505:
506: }
507:
508: private void renderMoveButtonRow(AddRemove component,
509: FacesContext context, ResponseWriter writer, String[] styles)
510: throws IOException {
511:
512: writer.startElement("table", component); //NOI18N
513: writer.writeAttribute("class", styles[10], null); //NOI18N
514: writer.writeText("\n", null); //NOI18N
515: writer.startElement("tr", component); //NOI18N
516: writer.writeAttribute("valign", "top", null); //NOI18N
517: writer.writeText("\n", null); //NOI18N
518:
519: renderButtonVertical(component, component
520: .getMoveUpButtonComponent(), styles[11], styles[20],
521: writer, context);
522: renderButtonVertical(component, component
523: .getMoveDownButtonComponent(), styles[12], styles[20],
524: writer, context);
525:
526: writer.endElement("tr"); //NOI18N
527: writer.writeText("\n", null); //NOI18N
528: writer.endElement("table"); //NOI18N
529: writer.writeText("\n", null); //NOI18N
530:
531: }
532:
533: private void renderButton(AddRemove addRemove, UIComponent comp,
534: String style, ResponseWriter writer, FacesContext context)
535: throws IOException {
536:
537: if (comp == null)
538: return;
539:
540: writer.startElement("div", addRemove); //NOI18N
541: writer.writeAttribute("class", style, null); //NOI18N
542: writer.writeText("\n", null); //NOI18N
543: if (comp.getParent() == null) {
544: comp.setParent(addRemove);
545: RenderingUtilities.renderComponent(comp, context);
546: comp.setParent(null);
547: } else {
548: RenderingUtilities.renderComponent(comp, context);
549: }
550: writer.writeText("\n", null); //NOI18N
551: writer.endElement("div"); //NOI18N
552: writer.writeText("\n", null); //NOI18N
553: }
554:
555: private void renderButtonVertical(AddRemove addRemove,
556: UIComponent comp, String style, String divStyle,
557: ResponseWriter writer, FacesContext context)
558: throws IOException {
559:
560: if (comp == null)
561: return;
562:
563: writer.startElement("td", addRemove); //NOI18N
564: writer.writeAttribute("class", divStyle, null); //NOI18N
565: writer.startElement("div", addRemove); //NOI18N
566: writer.writeAttribute("class", style, null); //NOI18N
567: writer.writeText("\n", null); //NOI18N
568: if (comp.getParent() == null) {
569: comp.setParent(addRemove);
570: RenderingUtilities.renderComponent(comp, context);
571: comp.setParent(null);
572: } else {
573: RenderingUtilities.renderComponent(comp, context);
574: }
575: writer.writeText("\n", null); //NOI18N
576: writer.endElement("div"); //NOI18N
577: writer.writeText("\n", null); //NOI18N
578: writer.endElement("td"); //NOI18N
579: writer.writeText("\n", null); //NOI18N
580: }
581:
582: /**
583: * This is the base method for rendering a HTML select
584: * element. This method is based on the functionality of the RI
585: * version, so it invokes a method renderSelectItems which in term
586: * invokes renderSelectItem. Currently, this renderer requires for
587: * the options to be specified using the JSF SelectItem construct,
588: * but this should be replaced with a Lockhart version, because
589: * the JSF version lacks the ability to associate an id with the
590: * list item. I'm not sure whether it should be possible to use
591: * SelectItem as well yet.
592: * @param component The UI Component associated with the
593: * renderer.
594: * @param context The FacesContext of the request
595: * @param styles A String array of styles used to render the
596: * component. The first item of the array is the name of the
597: * JavaScript method that handles change event. The second item is
598: * the style used when the list is enabled. The third style is the
599: * one to use when the list is disabled. The fourth item is the
600: * style to use for an item that is enabled, the fifth to use for
601: * an item that is disabled, and the sixth to use when the item is
602: * selected.
603: * @throws java.io.IOException if the renderer fails to write to
604: * the response
605: */
606: protected void renderAvailableList(AddRemove component,
607: FacesContext context, String[] styles) throws IOException {
608:
609: String id = component.getClientId(context).concat(AVAILABLE_ID);
610:
611: // Set the style class
612: String styleClass = styles[1];
613: if (component.isDisabled())
614: styleClass = styles[2];
615:
616: ResponseWriter writer = context.getResponseWriter();
617:
618: // This stuff is from the RI...
619: //Util.doAssert(writer != null);
620:
621: // This stuff is from the RI... Not sure what it is supposed to
622: // accomplish?
623: // String redisplay = "" + attributeMap.get("redisplay");
624:
625: // (redisplay == null || !redisplay.equals("true")) {
626: //currentValue = "";
627: //}
628:
629: writer.startElement("select", component); //NOI18N
630: writer.writeAttribute("class", styleClass, null); //NOI18N
631: writer.writeAttribute("id", id, null); //NOI18N
632: writer.writeAttribute("name", id, null); //NOI18N
633:
634: StringBuffer jsBuffer = new StringBuffer(200);
635: jsBuffer.append(AddRemove.JAVASCRIPT_PREFIX);
636: jsBuffer.append(component.getAttributes().get(
637: AddRemove.JSOBJECT));
638: jsBuffer.append(AddRemove.ADD_FUNCTION);
639: jsBuffer.append(AddRemove.RETURN);
640: writer.writeAttribute("ondblclick", jsBuffer.toString(), null);
641:
642: jsBuffer = new StringBuffer(200);
643: jsBuffer.append(AddRemove.JAVASCRIPT_PREFIX);
644: jsBuffer.append(component.getAttributes().get(
645: AddRemove.JSOBJECT));
646: jsBuffer.append(AddRemove.AVAILABLE_ONCHANGE_FUNCTION);
647: jsBuffer.append(AddRemove.RETURN);
648: writer.writeAttribute("onchange", jsBuffer.toString(), null);
649:
650: int size = component.getRows();
651: writer.writeAttribute("size", String.valueOf(size), null); //NOI18N
652: writer.writeAttribute("multiple", "multiple", null); //NOI18N
653:
654: if (component.isDisabled()) {
655: writer.writeAttribute("disabled", //NOI18N
656: "disabled", //NOI18N
657: "disabled"); //NOI18N
658: }
659:
660: String tooltip = component.getToolTip();
661: if (tooltip != null) {
662: writer.writeAttribute("title", tooltip, null); //NOI18N
663: }
664:
665: if (DEBUG)
666: log("Setting onchange event handler");
667: //writer.writeAttribute("onchange", script, null); //NOI18N
668:
669: int tabindex = component.getTabIndex();
670: if (tabindex > 0 && tabindex < 32767) {
671: writer.writeAttribute("tabindex", //NOI18N
672: String.valueOf(tabindex), "tabindex"); //NOI18N
673: }
674:
675: RenderingUtilities.writeStringAttributes(component, writer,
676: STRING_ATTRIBUTES);
677:
678: writer.writeText("\n", null); //NOI18N
679:
680: renderListOptions(component, component.getListItems(context,
681: true), writer, styles);
682:
683: writer.endElement("select"); //NOI18N
684: writer.writeText("\n", null); //NOI18N
685: }
686:
687: /**
688: * This is the base method for rendering a HTML select
689: * element. This method is based on the functionality of the RI
690: * version, so it invokes a method renderSelectItems which in term
691: * invokes renderSelectItem. Currently, this renderer requires for
692: * the options to be specified using the JSF SelectItem construct,
693: * but this should be replaced with a Lockhart version, because
694: * the JSF version lacks the ability to associate an id with the
695: * list item. I'm not sure whether it should be possible to use
696: * SelectItem as well yet.
697: * @param component The UI Component associated with the
698: * renderer.
699: * @param context The FacesContext of the request
700: * @param styles A String array of styles used to render the
701: * component. The first item of the array is the name of the
702: * JavaScript method that handles change event. The second item is
703: * the style used when the list is enabled. The third style is the
704: * one to use when the list is disabled. The fourth item is the
705: * style to use for an item that is enabled, the fifth to use for
706: * an item that is disabled, and the sixth to use when the item is
707: * selected.
708: * @throws java.io.IOException if the renderer fails to write to
709: * the response
710: */
711: protected void renderSelectedList(AddRemove component,
712: FacesContext context, String[] styles) throws IOException {
713:
714: String id = component.getClientId(context).concat(SELECTED_ID);
715:
716: // Set the style class
717: String styleClass = styles[1];
718: if (component.isDisabled()) {
719: styleClass = styles[2];
720: }
721:
722: ResponseWriter writer = context.getResponseWriter();
723:
724: // This stuff is from the RI...
725: //Util.doAssert(writer != null);
726:
727: // This stuff is from the RI... Not sure what it is supposed to
728: // accomplish?
729: // String redisplay = "" + attributeMap.get("redisplay");
730:
731: // (redisplay == null || !redisplay.equals("true")) {
732: //currentValue = "";
733: //}
734:
735: writer.startElement("select", component); //NOI18N
736: writer.writeAttribute("class", styleClass, null); //NOI18N
737: writer.writeAttribute("id", id, null); //NOI18N
738: writer.writeAttribute("size", //NOI18N
739: String.valueOf(component.getRows()), null);
740: writer.writeAttribute("multiple", "multiple", null); //NOI18N
741:
742: StringBuffer jsBuffer = new StringBuffer(200);
743: jsBuffer.append(AddRemove.JAVASCRIPT_PREFIX);
744: jsBuffer.append(component.getAttributes().get(
745: AddRemove.JSOBJECT));
746: jsBuffer.append(AddRemove.REMOVE_FUNCTION);
747: jsBuffer.append(AddRemove.RETURN);
748: writer.writeAttribute("ondblclick", jsBuffer.toString(), null); //NOI18N
749:
750: jsBuffer = new StringBuffer(200);
751: jsBuffer.append(AddRemove.JAVASCRIPT_PREFIX);
752: jsBuffer.append(component.getAttributes().get(
753: AddRemove.JSOBJECT));
754: jsBuffer.append(AddRemove.SELECTED_ONCHANGE_FUNCTION);
755: jsBuffer.append(AddRemove.RETURN);
756: writer.writeAttribute("onchange", jsBuffer.toString(), null); //NOI18N
757:
758: if (component.isDisabled()) {
759: writer.writeAttribute("disabled", //NOI18N
760: "disabled", //NOI18N
761: "disabled"); //NOI18N
762: }
763:
764: // TODO
765: /*
766: String tooltip = component.getToolTip();
767: if(tooltip != null) {
768: writer.writeAttribute("title", tooltip, null); //NOI18N
769: }
770: */
771:
772: if (DEBUG)
773: log("Setting onchange event handler");
774: /*
775: String script =
776: getJavaScript(component.getOnChange(),
777: styles[0],
778: id);
779: writer.writeAttribute("onchange", script, null); //NOI18N
780: */
781:
782: int tabindex = component.getTabIndex();
783: if (tabindex > 0 && tabindex < 32767) {
784: writer.writeAttribute("tabindex", //NOI18N
785: String.valueOf(tabindex), "tabindex"); //NOI18N
786: }
787:
788: RenderingUtilities.writeStringAttributes(component, writer,
789: STRING_ATTRIBUTES);
790: writer.writeText("\n", null); //NOI18N
791: renderListOptions(component, component.getSelectedListItems(),
792: writer, styles);
793: writer.endElement("select"); //NOI18N
794: writer.writeText("\n", null); //NOI18N
795: }
796:
797: /**
798: * Overrides encodeChildren of Renderer to do nothing. This
799: * renderer renders its own children, but not through this
800: * method.
801: * @param context The FacesContext of the request
802: * @param component The component associated with the
803: * renderer. Must be a subclass of ListSelector.
804: * @throws java.io.IOException if something goes wrong while writing the children
805: */
806: public void encodeChildren(
807: javax.faces.context.FacesContext context,
808: javax.faces.component.UIComponent component)
809: throws java.io.IOException {
810: return;
811: }
812:
813: /**
814: * <p>Render the appropriate element end, depending on the value of the
815: * <code>type</code> property.</p>
816: *
817: * @param context <code>FacesContext</code> for the current request
818: * @param monospace <code>UIComponent</code> if true, use the monospace
819: * styles to render the list.
820: *
821: * @exception IOException if an input/output error occurs
822: */
823: private String[] getStyles(FacesContext context) {
824:
825: if (DEBUG)
826: log("getStyles()");
827:
828: Theme theme = ThemeUtilities.getTheme(context);
829:
830: String[] styles = new String[21];
831: styles[0] = "listbox_changed"; //NOI18N
832: styles[1] = theme.getStyleClass(ThemeStyles.LIST);
833: styles[2] = theme.getStyleClass(ThemeStyles.LIST_DISABLED);
834: styles[3] = theme.getStyleClass(ThemeStyles.LIST_OPTION);
835: styles[4] = theme
836: .getStyleClass(ThemeStyles.LIST_OPTION_DISABLED);
837: styles[5] = theme
838: .getStyleClass(ThemeStyles.LIST_OPTION_SELECTED);
839: styles[6] = theme.getStyleClass(ThemeStyles.LIST_OPTION_GROUP);
840: styles[7] = theme
841: .getStyleClass(ThemeStyles.LIST_OPTION_SEPARATOR);
842: styles[8] = theme.getStyleClass(ThemeStyles.ADDREMOVE_LABEL);
843: styles[9] = theme.getStyleClass(ThemeStyles.ADDREMOVE_LABEL2);
844: styles[10] = theme
845: .getStyleClass(ThemeStyles.ADDREMOVE_BUTTON_TABLE);
846: styles[11] = theme
847: .getStyleClass(ThemeStyles.ADDREMOVE_VERTICAL_FIRST);
848: styles[12] = theme
849: .getStyleClass(ThemeStyles.ADDREMOVE_VERTICAL_WITHIN);
850: styles[13] = theme
851: .getStyleClass(ThemeStyles.ADDREMOVE_VERTICAL_BETWEEN);
852: styles[14] = theme
853: .getStyleClass(ThemeStyles.ADDREMOVE_HORIZONTAL_WITHIN);
854: styles[15] = theme
855: .getStyleClass(ThemeStyles.ADDREMOVE_HORIZONTAL_BETWEEN);
856: styles[16] = theme.getPathToJSFile(ThemeJavascript.ADD_REMOVE);
857: styles[17] = theme
858: .getStyleClass(ThemeStyles.ADDREMOVE_HORIZONTAL_ALIGN);
859: styles[18] = theme
860: .getStyleClass(ThemeStyles.ADDREMOVE_HORIZONTAL_LAST);
861: styles[19] = theme.getStyleClass(ThemeStyles.HIDDEN);
862: styles[20] = theme
863: .getStyleClass(ThemeStyles.ADDREMOVE_VERTICAL_BUTTON);
864: return styles;
865: }
866:
867: /**
868: * Decodes the value of the component
869: * @param context The FacesContext of the request
870: * @param component The component instance to be decoded
871: */
872: public void decode(FacesContext context, UIComponent component) {
873:
874: if (DEBUG)
875: log("decode()");
876: String id = component.getClientId(context).concat(
877: ListSelector.VALUE_ID);
878: super.decode(context, component, id);
879: }
880: }
|