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.text.DateFormat;
044: import java.io.IOException;
045: import java.util.MissingResourceException;
046:
047: import javax.faces.FacesException;
048: import javax.faces.context.FacesContext;
049: import javax.faces.context.ResponseWriter;
050: import javax.faces.component.UIComponent;
051:
052: import com.sun.rave.web.ui.component.Calendar;
053: import com.sun.rave.web.ui.component.CalendarMonth;
054: import com.sun.rave.web.ui.component.ImageHyperlink;
055: import com.sun.rave.web.ui.theme.Theme;
056: import com.sun.rave.web.ui.theme.ThemeImages;
057: import com.sun.rave.web.ui.theme.ThemeStyles;
058: import com.sun.rave.web.ui.theme.ThemeJavascript;
059: import com.sun.rave.web.ui.util.MessageUtil;
060: import com.sun.rave.web.ui.util.ConversionUtilities;
061: import com.sun.rave.web.ui.util.RenderingUtilities;
062: import com.sun.rave.web.ui.util.ThemeUtilities;
063: import java.text.SimpleDateFormat;
064:
065: /**
066: * <p>Renders an instance of the Calendar component.</p>
067: *
068: */
069: public class CalendarRenderer extends FieldRenderer {
070:
071: private final static boolean DEBUG = false;
072:
073: /** Creates a new instance of CalendarRenderer. */
074: public CalendarRenderer() {
075: }
076:
077: /**
078: * <p>Render the component end element.</p>
079: *
080: * @param context <code>FacesContext</code> for the current request
081: * @param component <code>UIComponent</code> to be rendered
082: * @exception IOException if an input/output error occurs
083: */
084: public void encodeEnd(FacesContext context, UIComponent component)
085: throws IOException {
086:
087: if (!(component instanceof Calendar)) {
088: Object[] params = { component.toString(),
089: this .getClass().getName(), Calendar.class.getName() };
090: String message = MessageUtil.getMessage(
091: "com.sun.rave.web.ui.resources.LogMessages", //NOI18N
092: "Renderer.component", params); //NOI18N
093: throw new FacesException(message);
094: }
095:
096: Calendar calendar = (Calendar) component;
097: boolean readOnly = calendar.isReadOnly();
098:
099: ResponseWriter writer = context.getResponseWriter();
100: String[] styles = getStyles(calendar, context);
101: String clientId = calendar.getClientId(context);
102:
103: // Write the JavaScript
104: includeJsFile(writer, calendar, styles[12]);
105:
106: // Start a table
107: renderTableStart(calendar, styles[18], styles[2], context,
108: writer);
109:
110: // Table cell for the label
111: UIComponent label = calendar.getLabelComponent(context, null);
112: if (label != null) {
113: renderCellStart(calendar, styles[6], writer);
114: RenderingUtilities.renderComponent(label, context);
115: renderCellEnd(writer);
116: }
117:
118: // Table cell for the field and the date format string
119:
120: if (readOnly) {
121: renderCellStart(calendar, styles[6], writer);
122: UIComponent text = calendar.getReadOnlyComponent(context);
123: RenderingUtilities.renderComponent(text, context);
124: if (calendar.getValue() != null) {
125: renderPattern(calendar, styles[7], styles[2], context,
126: writer);
127: }
128: } else {
129: renderCellStart(calendar, styles[4], writer);
130: renderInput(calendar, "text", clientId
131: .concat(calendar.INPUT_ID), false, styles, context,
132: writer);
133: writer.write("\n");
134: renderPattern(calendar, styles[7], styles[2], context,
135: writer);
136: }
137:
138: renderCellEnd(writer);
139:
140: if (!readOnly) {
141: // <rave> Fix popup so that it always appears near button. eeg 2005-11-04
142:
143: // Table cell for the link
144: //renderCellStart(calendar, styles[5], writer);
145:
146: // Start of table cell
147: writer.startElement("td", calendar);
148: writer.writeAttribute("valign", "top", null);//NOI18N
149: writer.writeText("\n", null);
150:
151: // Create a common CSS containing block used for positioning
152: writer.startElement("div", calendar);
153: writer.writeAttribute("style", "position: relative;", null);// NOI18N
154: writer.writeText("\n", null);
155:
156: // This is the span for the link
157: writer.startElement("span", calendar);
158: writer.writeAttribute("class", styles[5], null); //NOI18N
159: writer.writeText("\n", null);
160:
161: ImageHyperlink link = calendar.getDatePickerLink(context);
162: writer.startElement("span", calendar);
163: if (calendar.isDisabled()) {
164: writer.writeAttribute("style", "display:none;", null);
165: }
166: writer.write("\n");
167:
168: link.setIcon(styles[14]);
169: link.setAlt(styles[13]);
170: link.setToolTip(styles[13]);
171: RenderingUtilities.renderComponent(link, context);
172:
173: // Close span for disable
174: writer.endElement("span");
175: writer.write("\n");
176:
177: // Close link span
178: writer.endElement("span");
179: writer.write("\n");
180:
181: renderDatePicker(context, writer, styles, calendar);
182:
183: // Close remaining div and table cell
184: writer.endElement("div");
185: writer.writeText("\n", null);
186: writer.endElement("td");
187: writer.writeText("\n", null);
188: // </rave>
189: }
190: // End the table
191: renderTableEnd(writer);
192: writer.writeText("\n", null);
193: }
194:
195: // <rave> Fix popup so that it always appears near button. eeg 2005-11-04
196: private void renderDatePicker(FacesContext context,
197: ResponseWriter writer, String[] styles, Calendar calendar)
198: throws IOException {
199: // render date picker
200: CalendarMonth datePicker = calendar.getDatePicker();
201: Object value = calendar.getSubmittedValue();
202: if (value != null) {
203: try {
204: Object dO = ConversionUtilities.convertValueToObject(
205: calendar, (String) value, context);
206: datePicker.setValue(dO);
207: } catch (Exception ex) {
208: // do nothing
209: }
210: } else if (calendar.getValue() != null) {
211: datePicker.setValue(calendar.getValue());
212: }
213: datePicker.initCalendarControls(calendar
214: .getJavaScriptObjectName(context));
215: RenderingUtilities.renderComponent(datePicker, context);
216: //JS should be initialized by CalendarMonth, not by this component....
217: writer
218: .write(getJavaScriptInitializer(calendar, styles,
219: context));
220: }
221:
222: // </rave>
223:
224: private void renderTableStart(Calendar calendar, String rootStyle,
225: String hiddenStyle, FacesContext context,
226: ResponseWriter writer) throws IOException {
227:
228: writer.startElement("table", calendar);
229: writer.writeAttribute("border", "0", null); // NOI18N
230: writer.writeAttribute("cellspacing", "0", null); // NOI18N
231: writer.writeAttribute("cellpadding", "0", null); // NOI18N
232: writer.writeAttribute("title", "", null); // NOI18N
233: writer
234: .writeAttribute("id", calendar.getClientId(context),
235: "id"); //NOI18N
236: String style = calendar.getStyle();
237: if (style != null && style.length() > 0) {
238: writer.writeAttribute("style", style, "style"); //NOI18N
239: }
240:
241: style = getStyleClass(calendar, hiddenStyle);
242: // <RAVE>
243: // Append a styleclass to top level table element so we can use it to
244: // fix a pluto portal bug by restoring the initial width value
245: if (style == null) {
246: style = rootStyle;
247: } else {
248: style += " " + rootStyle;
249: }
250: // </RAVE>
251: if (style != null) {
252: writer.writeAttribute("class", style, "class"); //NOI18N
253: }
254: writer.writeText("\n", null);
255: writer.startElement("tr", calendar);
256: writer.writeText("\n", null);
257: }
258:
259: private void renderCellStart(Calendar calendar, String style,
260: ResponseWriter writer) throws IOException {
261:
262: writer.startElement("td", calendar);
263: writer.writeAttribute("valign", "top", null);//NOI18N
264: writer.writeText("\n", null);
265: writer.startElement("span", calendar);
266: writer.writeAttribute("class", style, null); //NOI18N
267: writer.writeText("\n", null);
268: }
269:
270: private void renderCellEnd(ResponseWriter writer)
271: throws IOException {
272:
273: writer.writeText("\n", null);
274: writer.endElement("span");
275: writer.writeText("\n", null);
276: writer.endElement("td");
277: writer.writeText("\n", null);
278: }
279:
280: private void renderTableEnd(ResponseWriter writer)
281: throws IOException {
282:
283: writer.endElement("tr"); //NOI18N
284: writer.writeText("\n", null); //NOI18N
285: writer.endElement("table"); //NOI18N
286: writer.writeText("\n", null); //NOI18N
287: }
288:
289: private void renderPattern(Calendar calendar, String styleClass,
290: String hiddenStyle, FacesContext context,
291: ResponseWriter writer) throws IOException {
292:
293: String hint = calendar.getDateFormatPatternHelp();
294: if (hint == null) {
295: String pattern = calendar.getDatePicker()
296: .getDateFormatPattern();
297:
298: try {
299: hint = ThemeUtilities.getTheme(context).getMessage(
300: "calendar.".concat(pattern));
301: } catch (MissingResourceException mre) {
302: hint = pattern.toLowerCase();
303: }
304: }
305: if (hint != null) {
306: writer.startElement("div", calendar); //NOI18N
307: String id = calendar.getClientId(context);
308: id = id.concat(Calendar.PATTERN_ID);
309: writer.writeAttribute("id", id, null); //NOI18N
310: String style = styleClass;
311: if (calendar.isDisabled()) {
312: style = style.concat(" ").concat(hiddenStyle);
313: }
314: writer.writeAttribute("class", style, null); //NOI18N
315: writer.writeText(hint, null);
316: writer.endElement("div"); //NOI18N
317: }
318: }
319:
320: // TODO - simplify this
321: private String getJavaScriptInitializer(Calendar calendar,
322: String[] styles, FacesContext context) {
323:
324: if (DEBUG)
325: log("getJavaScriptInitializer()"); //NOI18N
326:
327: // construct a buffer for the object js
328: String jsName = calendar.getJavaScriptObjectName(context);
329:
330: StringBuffer js = new StringBuffer(300);
331:
332: js.append("\n<script type=\"text/javascript\">\nvar ").append(
333: jsName).append(" = new ui_Calendar(");
334:
335: // First argument is the first day of the week
336:
337: int firstDay = calendar.getDatePicker().getCalendar()
338: .getFirstDayOfWeek();
339: String day = null;
340: if (firstDay == java.util.Calendar.SUNDAY) {
341: day = "0";
342: } else if (firstDay == java.util.Calendar.MONDAY) {
343: day = "1";
344: } else if (firstDay == java.util.Calendar.FRIDAY) {
345: day = "5";
346: } else if (firstDay == java.util.Calendar.SATURDAY) {
347: day = "6";
348: } else if (firstDay == java.util.Calendar.TUESDAY) {
349: day = "2";
350: } else if (firstDay == java.util.Calendar.WEDNESDAY) {
351: day = "3";
352: } else if (firstDay == java.util.Calendar.THURSDAY) {
353: day = "4";
354: }
355:
356: // Argument 1: first day of week
357: js.append(day).append(", '");
358:
359: // Argument 2: the ID of the field
360: js
361: .append(
362: calendar.getClientId(context).concat(
363: Calendar.INPUT_ID)).append("', '");
364:
365: // Argument 3: the ID of the pattern
366: js.append(
367: calendar.getClientId(context).concat(
368: Calendar.PATTERN_ID)).append("', '");
369:
370: // Argument 4: the ID of the image used as a link to open the
371: // calendar
372: js.append(
373: calendar.getDatePickerLink(context)
374: .getClientId(context)).append("', '");
375:
376: // Argument 5: the ID of the CalendarMonth component
377: String id = calendar.getDatePicker().getClientId(context);
378: js.append(id).append("', '");
379:
380: // Argument 6: month menu id
381: js.append(
382: calendar.getDatePicker().getMonthMenu().getClientId(
383: context)).append("', '");
384:
385: // Argument 7:
386: js.append(
387: calendar.getDatePicker().getYearMenu().getClientId(
388: context)).append("', '");
389:
390: // Argument 8: the last row id
391: js.append(id).append(":row5").append("', '");
392:
393: // Argument 9: the show button style
394: js.append(styles[8]).append("', '");
395:
396: // Argument 10: is the hide button style
397: js.append(styles[9]).append("', '");
398:
399: // Argument 11: dateformat pattern
400: js.append(calendar.getDatePicker().getDateFormatPattern())
401: .append("', '");
402:
403: // Argument 12: date link style
404: js.append(styles[10]).append("', '");
405:
406: // Argument 13: date link style
407: js.append(styles[11]).append("', '");
408:
409: // Argument 14: date link style
410: js.append(styles[15]).append("', '");
411:
412: // Argument 15: date link style
413: js.append(styles[16]).append("', '");
414:
415: // Argument 16: date link style
416: js.append(styles[17]).append("', '");
417:
418: // Argument 17: hidden style
419: js.append(styles[2]).append("');\n</script>\n");
420:
421: return js.toString();
422: }
423:
424: private void includeJsFile(ResponseWriter writer,
425: Calendar calendar, String src) throws IOException {
426: writer.startElement("script", calendar); //NOI18N
427: writer.writeAttribute("type", "text/javascript", null); //NOI18N
428: writer.writeAttribute("src", src, null); //NOI18N
429: writer.endElement("script"); //NOI18N
430: writer.write("\n"); //NOI18N
431: }
432:
433: String[] getStyles(Calendar calendar, FacesContext context) {
434: Theme theme = ThemeUtilities.getTheme(context);
435: String[] styles = new String[19];
436: styles[0] = theme.getStyleClass(ThemeStyles.TEXT_FIELD);
437: styles[1] = theme
438: .getStyleClass(ThemeStyles.TEXT_FIELD_DISABLED);
439: styles[2] = theme.getStyleClass(ThemeStyles.HIDDEN);
440: styles[3] = "";
441: styles[4] = ""; // used to be CalPopFld, removed
442: styles[5] = theme
443: .getStyleClass(ThemeStyles.CALENDAR_FIELD_IMAGE);
444: styles[6] = theme
445: .getStyleClass(ThemeStyles.CALENDAR_FIELD_LABEL);
446: styles[7] = theme.getStyleClass(ThemeStyles.HELP_FIELD_TEXT);
447: styles[8] = theme.getIcon(ThemeImages.CALENDAR_BUTTON).getUrl();
448: styles[9] = theme.getIcon(ThemeImages.CALENDAR_BUTTON_FLIP)
449: .getUrl();
450: styles[10] = theme.getStyleClass(ThemeStyles.DATE_TIME_LINK);
451: styles[11] = theme
452: .getStyleClass(ThemeStyles.DATE_TIME_OTHER_LINK);
453: styles[12] = theme.getPathToJSFile(ThemeJavascript.CALENDAR);
454: styles[13] = theme.getMessage("calendar.popupImageAlt");
455: styles[14] = ThemeImages.CALENDAR_BUTTON;
456: // Style for the selected date
457: styles[15] = theme
458: .getStyleClass(ThemeStyles.DATE_TIME_BOLD_LINK);
459: // Style for selected date on the edge
460: styles[16] = theme
461: .getStyleClass(ThemeStyles.DATE_TIME_OTHER_BOLD_LINK);
462: // Style for today's date
463: styles[17] = theme
464: .getStyleClass(ThemeStyles.DATE_TIME_TODAY_LINK);
465: // <RAVE>
466: styles[18] = theme
467: .getStyleClass(ThemeStyles.CALENDAR_ROOT_TABLE);
468: // </RAVE>
469: return styles;
470: }
471: }
|