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.Map;
045:
046: import javax.faces.FacesException;
047: import javax.faces.component.EditableValueHolder;
048: import javax.faces.component.UIComponent;
049: import javax.faces.context.FacesContext;
050: import javax.faces.context.ResponseWriter;
051: import com.sun.rave.web.ui.component.ListSelector;
052: import com.sun.rave.web.ui.component.OrderableList;
053: import com.sun.rave.web.ui.theme.Theme;
054: import com.sun.rave.web.ui.theme.ThemeJavascript;
055: import com.sun.rave.web.ui.theme.ThemeStyles;
056: import com.sun.rave.web.ui.util.RenderingUtilities;
057: import com.sun.rave.web.ui.util.ThemeUtilities;
058:
059: /**
060: *
061: * @author avk
062: */
063: public class OrderableListRenderer extends ListRendererBase {
064:
065: private final static boolean DEBUG = false;
066:
067: /**
068: * <p>Render the orderable list component
069: *
070: * @param context <code>FacesContext</code> for the current request
071: * @param component <code>UIComponent</code> to be rendered
072: * end should be rendered
073: *
074: * @exception IOException if an input/output error occurs
075: */
076: public void encodeEnd(FacesContext context, UIComponent component)
077: throws IOException {
078:
079: if (DEBUG)
080: log("encodeEnd()"); //NOI18N
081:
082: if (component instanceof OrderableList) {
083:
084: String jsID = component.getClientId(context);
085: String jsObject = null;
086: Object jsO = component.getAttributes().get(
087: OrderableList.JSOBJECT);
088: if (jsO == null) {
089: jsObject = jsID.replace(':', '_');
090: jsObject = "OrderableList_".concat(jsObject);
091: component.getAttributes().put(OrderableList.JSOBJECT,
092: jsObject);
093: } else {
094: jsObject = jsO.toString();
095: }
096:
097: renderListComponent((OrderableList) component, jsObject,
098: context, getStyles(component, context));
099: } else {
100: String message = "Component " + component.toString()
101: + //NOI18N
102: " has been associated with an OrderableListRenderer. "
103: + //NOI18N
104: " This renderer can only be used by components " + //NOI18N
105: " that extend com.sun.rave.web.ui.component.Selector."; //NOI18N
106: throw new FacesException(message);
107: }
108: }
109:
110: /**
111: * Retrieve user input from the UI.
112: * @param context The FacesContext of this request
113: * @param component The component associated with the renderer
114: */
115: public void decode(FacesContext context, UIComponent component) {
116:
117: if (DEBUG)
118: log("decode()");
119: String id = component.getClientId(context).concat(
120: ListSelector.VALUE_ID);
121: super .decode(context, component, id);
122:
123: if (DEBUG
124: && ((OrderableList) component).getSubmittedValue() != null) {
125: log("Submitted value is not null");
126: }
127: return;
128: }
129:
130: /**
131: * <p>This method determines whether the component should be
132: * rendered as a standalone list, or laid out together with a
133: * label that was defined as part of the component.</p>
134: *
135: * <p>A label will be rendered if either of the following is
136: * true:</p>
137: * <ul>
138: * <li>The page author defined a label facet; or</li>
139: * <li>The page author specified text in the label attribute.</li>
140: * </ul>
141: * <p>If there is a label, the component will be laid out using a
142: * HTML table. If not, the component will be rendered as a
143: * standalone HTML <tt>select</tt> element.</p>
144: * @param component The component associated with the
145: * renderer. Must be a subclass of ListSelector.
146: * @param context The FacesContext of the request
147: * @param styles A String array of styles used to render the
148: * component. The first item of the array is the name of the
149: * JavaScript method that handles change event. The second item is
150: * the style used when the list is enabled. The third style is the
151: * one to use when the list is disabled. The fourth item is the
152: * style to use for an item that is enabled, the fifth to use for
153: * an item that is disabled, and the sixth to use when the item is
154: * selected.
155: * @throws java.io.IOException if the renderer fails to write to
156: * the response
157: */
158: void renderListComponent(OrderableList component, String jsObject,
159: FacesContext context, String[] styles) throws IOException {
160:
161: if (DEBUG)
162: log("renderListComponent()");
163:
164: if (component.isReadOnly()) {
165: UIComponent label = component.getHeaderComponent();
166: super .renderReadOnlyList(component, label, context,
167: styles[15]);
168: return;
169: }
170:
171: ResponseWriter writer = context.getResponseWriter();
172:
173: // We should check if this one is already printed on the
174: // page...
175: writer.writeText("\n", null);
176: writer.startElement("script", component); // NOI18N
177: writer.writeAttribute("type", "text/javascript", null); // NOI18N
178: writer.writeURIAttribute("src", styles[13], null); // NOI18N
179: writer.endElement("script"); // NOI18N
180: writer.write("\n"); // NOI18N
181:
182: renderOpenEncloser(component, context, "div", styles[15]); //NOI18N
183:
184: // If the label goes on top, render it first...
185:
186: UIComponent headerComponent = component.getHeaderComponent();
187: if (headerComponent != null) {
188:
189: if (!component.isLabelOnTop()) {
190: writer.writeText("\n", null); //NOI18N
191: writer.startElement("span", component);
192: writer.writeAttribute("class", styles[10], null);
193: writer.writeText("\n", null); //NOI18N
194:
195: RenderingUtilities.renderComponent(headerComponent,
196: context);
197: writer.writeText("\n", null); //NOI18N
198: writer.endElement("span"); //NOI18N
199: writer.writeText("\n", null); //NOI18N
200: } else {
201: RenderingUtilities.renderComponent(headerComponent,
202: context);
203: writer.startElement("br", component); //NOI18N
204: writer.endElement("br"); //NOI18N
205: }
206: }
207:
208: // First column: available items
209: renderColumnTop(component, writer, styles[10]);
210: String id = component.getClientId(context).concat(
211: ListSelector.LIST_ID);
212: renderList(component, id, context, styles);
213: renderColumnBottom(writer);
214:
215: // Second column: button row
216: renderColumnTop(component, writer, styles[10]);
217: renderButtons(component, context, writer, styles);
218: renderColumnBottom(writer);
219:
220: writer.startElement("div", component); //NOI18N
221: writer.writeAttribute("class", styles[11], null); //NOI18N
222: writer.endElement("div"); //NOI18N
223:
224: UIComponent footerComponent = component
225: .getFacet(OrderableList.FOOTER_FACET);
226: if (footerComponent != null) {
227: writer.startElement("div", component); //NOI18N
228: writer.writeText("\n", null); //NOI18N
229: RenderingUtilities
230: .renderComponent(footerComponent, context);
231: writer.writeText("\n", null); //NOI18N
232: writer.endElement("div"); //NOI18N
233: writer.writeText("\n", null); //NOI18N
234: }
235:
236: String jsID = component.getClientId(context);
237:
238: // The value field
239: // Call super renderValueField ?
240: //
241: /*
242: RenderingUtilities.renderHiddenField
243: (component, writer, jsID.concat(VALUES_ID),
244: component.getValueAsString(context, component.getSeparator()));
245: */
246: renderHiddenValue(component, context, writer, styles[15]);
247:
248: writer.writeText("\n", null); //NOI18N
249: writer.endElement("div"); //NOI18N
250: writer.writeText("\n", null); //NOI18N
251:
252: // Initialize the JavaScript variable
253: StringBuffer jsBuffer = new StringBuffer(200);
254: jsBuffer.append("var "); //NOI18N
255: jsBuffer.append(jsObject);
256: jsBuffer.append(" = new OrderableList(\'"); //NOI18N
257: jsBuffer.append(jsID);
258: jsBuffer.append("\', \'"); //NOI18N
259: jsBuffer.append(styles[14]);
260: jsBuffer.append("\');\n"); //NOI18N
261: jsBuffer.append(jsObject);
262: jsBuffer.append(OrderableList.UPDATEBUTTONS_FUNCTION);
263:
264: writer.writeText("\n", null); //NOI18N
265: writer.startElement("script", component); // NOI18N
266: writer.writeAttribute("type", "text/javascript", null); // NOI18N
267: writer.writeText(jsBuffer.toString(), null);
268: writer.writeText("\n", null); //NOI18N
269: writer.endElement("script"); // NOI18N
270: writer.write("\n"); // NOI18N
271:
272: writer.writeText("\n", null); //NOI18N
273: writer.endElement("div"); //NOI18N
274: writer.writeText("\n", null); //NOI18N
275:
276: }
277:
278: private void renderColumnTop(OrderableList component,
279: ResponseWriter writer, String style) throws IOException {
280:
281: // Render the available elements
282: writer.startElement("div", component); //NOI18N
283: writer.writeAttribute("class", style, null); //NOI18N
284: writer.writeText("\n", null); //NOI18N
285: }
286:
287: private void renderColumnBottom(ResponseWriter writer)
288: throws IOException {
289: writer.writeText("\n", null); //NOI18N
290: writer.endElement("div"); //NOI18N
291: writer.writeText("\n", null); //NOI18N
292: }
293:
294: private void renderButtons(OrderableList component,
295: FacesContext context, ResponseWriter writer, String[] styles)
296: throws IOException {
297:
298: writer.writeText("\n", null); //NOI18N
299: writer.startElement("div", component); //NOI18N
300: String style = "padding-left:10;padding-right:10"; //NOI18N
301: writer.writeAttribute("style", style, null); //NOI18N
302: writer.writeText("\n", null); //NOI18N
303: writer.startElement("table", component); //NOI18N
304: writer.writeAttribute("class", styles[12], null); //NOI18N
305: writer.writeText("\n", null); //NOI18N
306: writer.startElement("tr", component); //NOI18N
307: writer.writeText("\n", null); //NOI18N
308: writer.startElement("td", component); //NOI18N
309: writer.writeAttribute("align", "center", null); //NOI18N
310: writer.writeAttribute("width", "125", null); //NOI18N
311: writer.writeText("\n", null); //NOI18N
312: RenderingUtilities.renderComponent(component
313: .getMoveUpButtonComponent(context), context);
314: writer.writeText("\n", null); //NOI18N
315:
316: renderButton(component, component
317: .getMoveDownButtonComponent(context), styles[9],
318: writer, context);
319:
320: if (component.isMoveTopBottom()) {
321: renderButton(component, component
322: .getMoveTopButtonComponent(context), styles[8],
323: writer, context);
324: renderButton(component, component
325: .getMoveBottomButtonComponent(context), styles[9],
326: writer, context);
327: }
328:
329: writer.endElement("td"); //NOI18N
330: writer.writeText("\n", null); //NOI18N
331: writer.endElement("tr"); //NOI18N
332: writer.writeText("\n", null); //NOI18N
333: writer.endElement("table"); //NOI18N
334: writer.writeText("\n", null); //NOI18N
335: writer.endElement("div"); //NOI18N
336: writer.writeText("\n", null); //NOI18N
337: }
338:
339: private void renderButton(OrderableList list, UIComponent comp,
340: String style, ResponseWriter writer, FacesContext context)
341: throws IOException {
342:
343: if (comp == null)
344: return;
345:
346: writer.startElement("div", list); //NOI18N
347: writer.writeAttribute("class", style, null); //NOI18N
348: writer.writeText("\n", null); //NOI18N
349: RenderingUtilities.renderComponent(comp, context);
350: writer.writeText("\n", null); //NOI18N
351: writer.endElement("div"); //NOI18N
352: writer.writeText("\n", null); //NOI18N
353: }
354:
355: /**
356: * Overrides encodeChildren of Renderer to do nothing. This
357: * renderer renders its own children, but not through this
358: * method.
359: * @param context The FacesContext of the request
360: * @param component The component associated with the
361: * renderer. Must be a subclass of ListSelector.
362: */
363: public void encodeChildren(
364: javax.faces.context.FacesContext context,
365: javax.faces.component.UIComponent component)
366: throws java.io.IOException {
367: return;
368: }
369:
370: /**
371: * <p>Renders a component in a table row.</p>
372: * @param component The component
373: * @param context The FacesContext of the request
374: * @throws java.io.IOException if the renderer fails to write to
375: * the response
376: */
377: private void addComponentSingleRow(OrderableList list,
378: UIComponent component, FacesContext context)
379: throws IOException {
380:
381: ResponseWriter writer = context.getResponseWriter();
382: writer.startElement("tr", list); //NOI18N
383: writer.writeText("\n", null); //NOI18N
384: writer.startElement("td", list); //NOI18N
385: RenderingUtilities.renderComponent(component, context);
386: writer.writeText("\n", null); //NOI18N
387: // Perhaps this should depend on the dir?
388: // writer.writeAttribute("align", "left", null);
389: writer.endElement("td"); //NOI18N
390: writer.writeText("\n", null); //NOI18N
391: writer.endElement("tr"); //NOI18N
392: writer.writeText("\n", null); //NOI18N
393: }
394:
395: /**
396: * <p>Render the appropriate element end, depending on the value of the
397: * <code>type</code> property.</p>
398: *
399: * @param context <code>FacesContext</code> for the current request
400: * @param monospace <code>UIComponent</code> if true, use the monospace
401: * styles to render the list.
402: *
403: * @exception IOException if an input/output error occurs
404: */
405: private String[] getStyles(UIComponent component,
406: FacesContext context) {
407:
408: if (DEBUG)
409: log("getStyles()");
410:
411: Theme theme = ThemeUtilities.getTheme(context);
412:
413: StringBuffer jsBuffer = new StringBuffer(200);
414: jsBuffer = new StringBuffer(200);
415: jsBuffer.append(OrderableList.JAVASCRIPT_PREFIX);
416: jsBuffer.append(component.getAttributes().get(
417: OrderableList.JSOBJECT));
418: jsBuffer.append(OrderableList.ONCHANGE_FUNCTION);
419: jsBuffer.append(OrderableList.RETURN);
420:
421: String[] styles = new String[16];
422:
423: styles[0] = jsBuffer.toString();
424: styles[1] = theme.getStyleClass(ThemeStyles.LIST);
425: styles[2] = theme.getStyleClass(ThemeStyles.LIST_DISABLED);
426: styles[3] = theme.getStyleClass(ThemeStyles.LIST_OPTION);
427: styles[4] = theme
428: .getStyleClass(ThemeStyles.LIST_OPTION_DISABLED);
429: styles[5] = theme
430: .getStyleClass(ThemeStyles.LIST_OPTION_SELECTED);
431: styles[6] = theme.getStyleClass(ThemeStyles.LIST_OPTION_GROUP);
432: styles[7] = theme
433: .getStyleClass(ThemeStyles.LIST_OPTION_SEPARATOR);
434: styles[8] = theme
435: .getStyleClass(ThemeStyles.ADDREMOVE_HORIZONTAL_BETWEEN);
436: styles[9] = theme
437: .getStyleClass(ThemeStyles.ADDREMOVE_HORIZONTAL_WITHIN);
438: styles[10] = theme
439: .getStyleClass(ThemeStyles.ADDREMOVE_HORIZONTAL_ALIGN);
440: styles[11] = theme
441: .getStyleClass(ThemeStyles.ADDREMOVE_HORIZONTAL_LAST);
442: styles[12] = theme
443: .getStyleClass(ThemeStyles.ADDREMOVE_BUTTON_TABLE);
444: styles[13] = theme
445: .getPathToJSFile(ThemeJavascript.ORDERABLE_LIST);
446: styles[14] = theme.getMessage("OrderableList.moveMessage"); //NOI18N
447: styles[15] = theme.getStyleClass(ThemeStyles.HIDDEN);
448: return styles;
449: }
450: }
|