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.component;
042:
043: import java.io.Serializable;
044: import java.util.Calendar;
045: import java.util.Locale;
046: import java.util.TimeZone;
047: import javax.faces.application.FacesMessage;
048: import javax.faces.component.EditableValueHolder;
049: import javax.faces.component.NamingContainer;
050: import javax.faces.component.UIComponent;
051: import javax.faces.context.FacesContext;
052: import javax.faces.convert.ConverterException;
053: import javax.faces.convert.IntegerConverter;
054: import javax.faces.event.ValueChangeEvent;
055: import com.sun.rave.web.ui.model.ClockTime;
056: import com.sun.rave.web.ui.model.Option;
057: import com.sun.rave.web.ui.model.OptionTitle;
058: import com.sun.rave.web.ui.theme.Theme;
059: import com.sun.rave.web.ui.util.ThemeUtilities;
060:
061: /**
062: *
063: * @author avk
064: */
065: public class Time extends TimeBase implements NamingContainer {
066:
067: public static final String HOUR_FACET = "hour";
068: public static final String HOUR_ID = "_hour";
069:
070: public static final String MINUTES_FACET = "minutes";
071: public static final String MINUTES_ID = "_minutes";
072:
073: private static final String TIME_SUBMITTED = "com.sun.rave.web.ui.TimeSubmitted";
074:
075: private static final boolean DEBUG = false;
076:
077: public DropDown getHourMenu() {
078: return getMenu(HOUR_ID, HOUR_FACET, getHourItems());
079: }
080:
081: public DropDown getMinutesMenu() {
082: return getMenu(MINUTES_ID, MINUTES_FACET, getMinuteItems());
083: }
084:
085: private DropDown getMenu(String id, String facet, Option[] options) {
086:
087: if (DEBUG)
088: log("getMenu() for facet " + facet);
089:
090: // Check if the page author has defined a label facet
091: UIComponent comp = getFacet(facet);
092: if (comp != null && comp instanceof DropDown) {
093: if (DEBUG)
094: log("Found facet");
095: return (DropDown) comp;
096: }
097:
098: DropDown menu = createDropDown(id, facet, options);
099: menu.setDisabled(isDisabled());
100: menu.setRequired(isRequired());
101: return menu;
102: }
103:
104: // Component creation methods
105: private DropDown createDropDown(String id, String facetName,
106: Option[] items) {
107:
108: if (DEBUG)
109: log("createDropDown() for facet " + facetName);
110:
111: DropDown dropDown = new DropDown();
112: dropDown.setId(getId().concat(id));
113: dropDown.setItems(items);
114: dropDown.setConverter(new IntegerConverter());
115:
116: if (getTabIndex() > 0) {
117: dropDown.setTabIndex(getTabIndex());
118: }
119:
120: getFacets().put(facetName, dropDown);
121: return dropDown;
122: }
123:
124: /**
125: * <p>Convenience method to return at Option[] with all of the hours
126: * defined in 24 hourObject format.</p>
127: *
128: * @return An Option[] containing all the hours
129: */
130: private Option[] getHourItems() {
131: Option[] hours = new Option[25];
132:
133: hours[0] = new Option(new Integer(-1), " ");
134:
135: int counter = 0;
136: while (counter < 10) {
137: hours[counter + 1] = new Option(new Integer(counter), "0"
138: + counter);
139: ++counter;
140: }
141: while (counter < 24) {
142: hours[counter + 1] = new Option(new Integer(counter),
143: String.valueOf(counter));
144: ++counter;
145: }
146: return hours;
147: }
148:
149: /**
150: * <p>Convenience method to return at Option[] with all of the mintes (in
151: * 5 minuteObject increments) for an hourObject.</p>
152: *
153: * @return An Option[] containing all the minutes
154: */
155: private Option[] getMinuteItems() {
156: Option[] minutes = new Option[13];
157:
158: minutes[0] = new Option(new Integer(-1), " ");
159: minutes[1] = new Option(new Integer(0), "00");
160: minutes[2] = new Option(new Integer(5), "05");
161:
162: for (int i = 2; i < 12; i++) {
163: minutes[i + 1] = new Option(new Integer(5 * i), String
164: .valueOf(5 * i));
165: }
166:
167: return minutes;
168: }
169:
170: /**
171: * <p>Get the time-zone as a string.</p>
172: */
173: public String getOffset() {
174:
175: java.util.Calendar calendar = getCalendar();
176: TimeZone timeZone = calendar.getTimeZone();
177:
178: StringBuffer gmtTimeZone = new StringBuffer(8);
179:
180: int value = calendar.get(java.util.Calendar.ZONE_OFFSET)
181: + calendar.get(java.util.Calendar.DST_OFFSET);
182:
183: if (value < 0) {
184: // GMT - hh:mm
185: gmtTimeZone.append('-');
186: value = -value;
187: } else {
188: // GMT + hh:mm
189: gmtTimeZone.append('+');
190: }
191:
192: // determine the offset hours
193: int num = value / (1000 * 60 * 60);
194:
195: if (num < 10) {
196: // display offset as GMT + 0h:mm
197: gmtTimeZone.append("0");
198: }
199:
200: // add the hh: part
201: gmtTimeZone.append(num).append(":");
202:
203: // determine the offset minutes
204: num = (value % (1000 * 60 * 60)) / (1000 * 60);
205: if (num < 10) {
206: // display as hh:0m
207: gmtTimeZone.append("0");
208: }
209:
210: // append the minutes
211: gmtTimeZone.append(num);
212:
213: return gmtTimeZone.toString();
214: }
215:
216: /**
217: * <p>Returns a new Calendar instance corresponding to the user's current
218: * locale and the developer specified time zone (if any).</p>
219: *
220: * @return java.util.Calendar A new Calendar instance with the correct
221: * locale and time zone.
222: */
223: public java.util.Calendar getCalendar() {
224: java.util.Calendar calendar = null;
225: Locale locale = FacesContext.getCurrentInstance().getViewRoot()
226: .getLocale();
227: if (locale == null) {
228: locale = locale.getDefault();
229: }
230:
231: TimeZone timeZone = getTimeZone();
232:
233: if (timeZone == null) {
234: calendar = java.util.Calendar.getInstance(locale);
235: } else {
236: calendar = java.util.Calendar.getInstance(timeZone, locale);
237: }
238: return calendar;
239: }
240:
241: /**
242: * Holds value of property hourTooltipKey.
243: */
244: private String hourTooltipKey;
245:
246: /**
247: * Getter for property hourTooltipKey.
248: * @return Value of property hourTooltipKey.
249: */
250: public String getHourTooltipKey() {
251:
252: return this .hourTooltipKey;
253: }
254:
255: /**
256: * Setter for property hourTooltipKey.
257: * @param hourTooltipKey New value of property hourTooltipKey.
258: */
259: public void setHourTooltipKey(String hourTooltipKey) {
260:
261: this .hourTooltipKey = hourTooltipKey;
262: }
263:
264: /**
265: * Holds value of property minutesTooltipKey.
266: */
267: private String minutesTooltipKey;
268:
269: /**
270: * Getter for property minutesTooltipKey.
271: * @return Value of property minutesTooltipKey.
272: */
273: public String getMinutesTooltipKey() {
274:
275: return this .minutesTooltipKey;
276: }
277:
278: /**
279: * Setter for property minutesTooltipKey.
280: * @param minutesTooltipKey New value of property minutesTooltipKey.
281: */
282: public void setMinutesTooltipKey(String minutesTooltipKey) {
283:
284: this .minutesTooltipKey = minutesTooltipKey;
285: }
286:
287: /**
288: * <p>Specialized decode behavior on top of that provided by the
289: * superclass. In addition to the standard
290: * <code>processDecodes</code> behavior inherited from {@link
291: * UIComponentBase}, calls <code>validate()</code> if the the
292: * <code>immediate</code> property is true; if the component is
293: * invalid afterwards or a <code>RuntimeException</code> is thrown,
294: * calls {@link FacesContext#renderResponse}. </p>
295: * @exception NullPointerException
296: */
297: public void processDecodes(FacesContext context) {
298:
299: if (DEBUG)
300: log("processDecodes");
301:
302: if (context == null) {
303: throw new NullPointerException();
304: }
305:
306: // Skip processing if our rendered flag is false
307: if (!isRendered()) {
308: return;
309: }
310:
311: setValid(true);
312: getFacet(HOUR_FACET).processDecodes(context);
313: getFacet(MINUTES_FACET).processDecodes(context);
314: setSubmittedValue(TIME_SUBMITTED);
315:
316: // There is nothing to decode other than the facets
317:
318: if (isImmediate()) {
319: if (DEBUG)
320: log("Time is immediate");
321: runValidation(context);
322: }
323: }
324:
325: /**
326: * <p>Perform the following algorithm to validate the local value of
327: * this {@link UIInput}.</p>
328: *
329: * @param context The {@link FacesContext} for the current request
330: *
331: */
332: public void validate(FacesContext context) {
333:
334: if (DEBUG)
335: log("validate()");
336:
337: if (context == null) {
338: throw new NullPointerException();
339: }
340:
341: Object hourValue = getHourMenu().getValue();
342: if (DEBUG)
343: log("Hour value is " + String.valueOf(hourValue));
344:
345: Object minuteValue = getMinutesMenu().getValue();
346: if (DEBUG)
347: log("Minute value is " + String.valueOf(minuteValue));
348:
349: ClockTime newValue = null;
350:
351: try {
352: newValue = createClockTime(hourValue, minuteValue, context);
353: if (DEBUG)
354: log("Created ClockTime");
355: } catch (ConverterException ce) {
356: FacesMessage message = ce.getFacesMessage();
357: message.setSeverity(FacesMessage.SEVERITY_ERROR);
358: context.addMessage(getClientId(context), message);
359: setValid(false);
360: context.renderResponse();
361: } catch (Exception ex) {
362: // TODO - message
363: FacesMessage message = new FacesMessage("Invalid input");
364: message.setSeverity(FacesMessage.SEVERITY_ERROR);
365: context.addMessage(getClientId(context), message);
366: setValid(false);
367: context.renderResponse();
368: }
369:
370: // If our value is valid, store the new value, erase the
371: // "submitted" value, and emit a ValueChangeEvent if appropriate
372: if (isValid()) {
373: if (DEBUG)
374: log("\tComponent is valid");
375: Object previous = getValue();
376: setValue(newValue);
377: if (DEBUG)
378: log("\tNew value: " + String.valueOf(newValue));
379: setSubmittedValue(null);
380: if (compareValues(previous, newValue)) {
381: queueEvent(new ValueChangeEvent(this , previous,
382: newValue));
383: }
384: }
385: }
386:
387: private void runValidation(FacesContext context) {
388:
389: if (DEBUG)
390: log("runValidation()");
391:
392: try {
393: validate(context);
394: } catch (RuntimeException e) {
395: context.renderResponse();
396: throw e;
397: }
398:
399: if (!isValid()) {
400: if (DEBUG)
401: log("\tnot valid");
402: context.renderResponse();
403: }
404: }
405:
406: private ClockTime createClockTime(Object hourObject,
407: Object minuteObject, FacesContext context) {
408:
409: if (DEBUG)
410: log("CreateClockTime()");
411:
412: String messageKey = null;
413: ClockTime time = null;
414:
415: if (hourObject instanceof Integer
416: && minuteObject instanceof Integer) {
417:
418: if (DEBUG)
419: log("Found integers");
420:
421: int hour = ((Integer) hourObject).intValue();
422: int minute = ((Integer) minuteObject).intValue();
423:
424: if (hour == -1 && minute == -1) {
425: if (DEBUG)
426: log("No selections made");
427: if (isRequired()) {
428: messageKey = "Time.required";
429: } else {
430: return null;
431: }
432: }
433:
434: else if (hour == -1) {
435: messageKey = "Time.enterHour";
436: } else if (minute == -1) {
437: messageKey = "Time.enterMinute";
438: } else {
439: time = new ClockTime();
440: try {
441: if (DEBUG)
442: log("Hour is " + hour);
443: if (DEBUG)
444: log("Minute is " + minute);
445: time.setHour(new Integer(hour));
446: time.setMinute(new Integer(minute));
447: } catch (Exception ex) {
448: if (DEBUG) {
449: ex.printStackTrace();
450: }
451: messageKey = "Time.invalidData";
452: }
453: }
454: } else {
455: if (isRequired()) {
456: messageKey = "Time.required";
457: } else {
458: return null;
459: }
460:
461: }
462:
463: if (messageKey != null) {
464: if (DEBUG)
465: log("Invalid input");
466: String message = ThemeUtilities.getTheme(context)
467: .getMessage(messageKey);
468: throw new ConverterException(new FacesMessage(message));
469: }
470: return time;
471: }
472:
473: private void log(String s) {
474: System.out.println(this .getClass().getName() + "::" + s);
475: }
476:
477: /*
478: public void setValue(Object value) {
479: if(DEBUG) log("setValue(" + String.valueOf(value) + ")");
480: Thread.dumpStack();
481: super.setValue(value);
482: }
483:
484: public Object getValue() {
485: Object value = super.getValue();
486: if(DEBUG) log("getValue() ->" + String.valueOf(value));
487: return value;
488: }
489: */
490: }
|