Source Code Cross Referenced for DatePicker.java in  » J2EE » wicket » org » apache » wicket » extensions » yui » calendar » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » wicket » org.apache.wicket.extensions.yui.calendar 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:        package org.apache.wicket.extensions.yui.calendar;
018:
019:        import java.text.DateFormat;
020:        import java.text.DateFormatSymbols;
021:        import java.text.SimpleDateFormat;
022:        import java.util.ArrayList;
023:        import java.util.Date;
024:        import java.util.HashMap;
025:        import java.util.Iterator;
026:        import java.util.List;
027:        import java.util.Locale;
028:        import java.util.Map;
029:        import java.util.Properties;
030:        import java.util.Map.Entry;
031:
032:        import org.apache.wicket.Component;
033:        import org.apache.wicket.RequestCycle;
034:        import org.apache.wicket.ResourceReference;
035:        import org.apache.wicket.Response;
036:        import org.apache.wicket.WicketRuntimeException;
037:        import org.apache.wicket.ajax.AjaxEventBehavior;
038:        import org.apache.wicket.behavior.AbstractBehavior;
039:        import org.apache.wicket.datetime.markup.html.form.DateTextField;
040:        import org.apache.wicket.extensions.yui.YuiLib;
041:        import org.apache.wicket.markup.html.IHeaderContributor;
042:        import org.apache.wicket.markup.html.IHeaderResponse;
043:        import org.apache.wicket.markup.html.form.AbstractTextComponent.ITextFormatProvider;
044:        import org.apache.wicket.markup.html.resources.CompressedResourceReference;
045:        import org.apache.wicket.markup.html.resources.JavascriptResourceReference;
046:        import org.apache.wicket.util.convert.IConverter;
047:        import org.apache.wicket.util.convert.converters.DateConverter;
048:        import org.apache.wicket.util.string.Strings;
049:        import org.apache.wicket.util.template.PackagedTextTemplate;
050:        import org.apache.wicket.util.template.TextTemplate;
051:        import org.joda.time.DateTime;
052:
053:        /**
054:         * Pops up a YUI calendar component so that the user can select a date. On
055:         * selection, the date is set in the component it is coupled to, after which the
056:         * popup is closed again. This behavior can only be used with components that
057:         * either implement {@link ITextFormatProvider} or that use
058:         * {@link DateConverter} configured with an instance of {@link SimpleDateFormat}
059:         * (like Wicket's default configuration has).
060:         * 
061:         * To use, simply add a new instance to your component, which would typically a
062:         * TextField, like {@link DateTextField}.
063:         * 
064:         * @author eelcohillenius
065:         */
066:        public class DatePicker extends AbstractBehavior implements 
067:                IHeaderContributor {
068:            /**
069:             * Exception thrown when the bound component does not produce a format this
070:             * date picker can work with.
071:             */
072:            private static final class UnableToDetermineFormatException extends
073:                    WicketRuntimeException {
074:                private static final long serialVersionUID = 1L;
075:
076:                public UnableToDetermineFormatException() {
077:                    super (
078:                            "This behavior can only be added to components that either implement "
079:                                    + ITextFormatProvider.class.getName()
080:                                    + " AND produce a non-null format, or that use"
081:                                    + " converters that this datepicker can use to determine"
082:                                    + " the pattern being used. Alternatively, you can extend "
083:                                    + " the date picker and override getDatePattern to provide your own");
084:                }
085:            }
086:
087:            /**
088:             * Format to be used when configuring YUI calendar. Can be used when using
089:             * the "selected" property.
090:             */
091:            public static final DateFormat FORMAT_DATE = new SimpleDateFormat(
092:                    "MM/dd/yyyy");
093:
094:            /**
095:             * For specifying which page (month/year) to show in the calendar, use this
096:             * format for the date. This is to be used together with the property
097:             * "pagedate"
098:             */
099:            public static final DateFormat FORMAT_PAGEDATE = new SimpleDateFormat(
100:                    "MM/yyyy");
101:
102:            private static final long serialVersionUID = 1L;
103:
104:            /** The target component. */
105:            private Component component;
106:
107:            /**
108:             * Construct.
109:             */
110:            public DatePicker() {
111:            }
112:
113:            /**
114:             * @see org.apache.wicket.behavior.AbstractBehavior#bind(org.apache.wicket.Component)
115:             */
116:            public void bind(Component component) {
117:                this .component = component;
118:                checkComponentProvidesDateFormat(component);
119:                component.setOutputMarkupId(true);
120:            }
121:
122:            /**
123:             * @see org.apache.wicket.behavior.AbstractBehavior#onRendered(org.apache.wicket.Component)
124:             */
125:            public void onRendered(Component component) {
126:                super .onRendered(component);
127:                // Append the span and img icon right after the rendering of the
128:                // component. Not as pretty as working with a panel etc, but works
129:                // for behaviors and is more efficient
130:                Response response = component.getResponse();
131:                response
132:                        .write("\n<span class=\"yui-skin-sam\">&nbsp;<div style=\"display:none;position:absolute;z-index: 99999;\" id=\"");
133:                response.write(getEscapedComponentMarkupId());
134:                response.write("Dp\"></div><img style=\"");
135:                response.write(getIconStyle());
136:                response.write("\" id=\"");
137:                response.write(getIconId());
138:                response.write("\" src=\"");
139:                CharSequence iconUrl = getIconUrl();
140:                response.write(Strings.escapeMarkup(iconUrl != null ? iconUrl
141:                        .toString() : ""));
142:                response.write("\" /></span><input type=\"hidden\"/>");
143:            }
144:
145:            /**
146:             * @see org.apache.wicket.markup.html.IHeaderContributor#renderHead(org.apache.wicket.markup.html.IHeaderResponse)
147:             */
148:            public void renderHead(IHeaderResponse response) {
149:                YuiLib.load(response);
150:                if (enableMonthYearSelection()) {
151:                    response
152:                            .renderCSSReference(new CompressedResourceReference(
153:                                    DatePicker.class,
154:                                    "assets/wicket-calendar.css"));
155:                }
156:
157:                // variables for the initialization script
158:                Map variables = new HashMap();
159:                String widgetId = getEscapedComponentMarkupId();
160:                variables.put("componentId", getComponentMarkupId());
161:                variables.put("widgetId", widgetId);
162:                variables.put("datePattern", getDatePattern());
163:                variables.put("fireChangeEvent", Boolean
164:                        .valueOf(notifyComponentOnDateSelected()));
165:                variables
166:                        .put("alignWithIcon", Boolean.valueOf(alignWithIcon()));
167:                // variables for YUILoader
168:                variables.put("pathToWicketDate", RequestCycle.get().urlFor(
169:                        new JavascriptResourceReference(DatePicker.class,
170:                                "wicket-date.js")));
171:                variables.put("basePath", RequestCycle.get().urlFor(
172:                        new JavascriptResourceReference(YuiLib.class, "")));
173:                variables.put("enableMonthYearSelection", Boolean
174:                        .valueOf(enableMonthYearSelection()));
175:
176:                // print out the initialization properties
177:                Properties p = new Properties();
178:                configure(p);
179:
180:                // ${calendarInit}
181:                StringBuffer calendarInit = new StringBuffer();
182:                for (Iterator i = p.entrySet().iterator(); i.hasNext();) {
183:                    Entry entry = (Entry) i.next();
184:                    calendarInit.append(entry.getKey());
185:                    Object value = entry.getValue();
186:                    if (value instanceof  CharSequence) {
187:                        calendarInit.append(":\"");
188:                        calendarInit.append(Strings.toEscapedUnicode(value
189:                                .toString()));
190:                        calendarInit.append("\"");
191:                    } else if (value instanceof  CharSequence[]) {
192:                        calendarInit.append(":[");
193:                        CharSequence[] valueArray = (CharSequence[]) value;
194:                        for (int j = 0; j < valueArray.length; j++) {
195:                            CharSequence tmpValue = valueArray[j];
196:                            if (j > 0) {
197:                                calendarInit.append(",");
198:                            }
199:                            if (tmpValue != null) {
200:                                calendarInit.append("\"");
201:                                calendarInit.append(Strings
202:                                        .toEscapedUnicode(tmpValue.toString()));
203:                                calendarInit.append("\"");
204:                            }
205:                        }
206:                        calendarInit.append("]");
207:                    } else {
208:                        calendarInit.append(":");
209:                        calendarInit.append(Strings.toEscapedUnicode(String
210:                                .valueOf(value)));
211:                    }
212:                    if (i.hasNext()) {
213:                        calendarInit.append(",");
214:                    }
215:                }
216:                variables.put("calendarInit", calendarInit.toString());
217:
218:                // render initialization script with the variables interpolated
219:                TextTemplate datePickerJs = new PackagedTextTemplate(
220:                        DatePicker.class, "DatePicker.js");
221:                datePickerJs.interpolate(variables);
222:                response.renderOnDomReadyJavascript(datePickerJs.asString());
223:            }
224:
225:            /**
226:             * Check that this behavior can get a date format out of the component it is
227:             * coupled to. It checks whether {@link #getDatePattern()} produces a
228:             * non-null value. If that method returns null, and exception will be thrown
229:             * 
230:             * @param component
231:             *            the component this behavior is being coupled to
232:             * @throws UnableToDetermineFormatException
233:             *             if this date picker is unable to determine a format.
234:             */
235:            private final void checkComponentProvidesDateFormat(
236:                    Component component) {
237:                if (getDatePattern() == null) {
238:                    throw new UnableToDetermineFormatException();
239:                }
240:            }
241:
242:            /**
243:             * Set widget property if the array is null and has a length greater than 0.
244:             * 
245:             * @param widgetProperties
246:             * @param key
247:             * @param array
248:             */
249:            private void setWidgetProperty(Map widgetProperties, String key,
250:                    String[] array) {
251:                if (array != null && array.length > 0) {
252:                    widgetProperties.put(key, array);
253:                }
254:            }
255:
256:            /**
257:             * Whether to position the date picker relative to the trigger icon.
258:             * 
259:             * @return If true, the date picker is aligned with the left position of the
260:             *         icon, and with the top right under. If false, the date picker
261:             *         will skip positioning and will let you do the positioning
262:             *         yourself. Returns true by default.
263:             */
264:            protected boolean alignWithIcon() {
265:                return true;
266:            }
267:
268:            /**
269:             * Append javascript to the initialization function for the YUI widget. Can
270:             * be used by subclasses to conveniently extend configuration without having
271:             * to write a separate contribution.
272:             * 
273:             * @param markupId
274:             *            The markup id of the calendar component
275:             * @param javascriptId
276:             *            the non-name spaced javascript id of the widget
277:             * @param javascriptWidgetId
278:             *            the name space id of the widget
279:             * @param b
280:             *            the buffer to append the script to
281:             */
282:            protected void appendToInit(String markupId, String javascriptId,
283:                    String javascriptWidgetId, StringBuffer b) {
284:            }
285:
286:            /**
287:             * Gives overriding classes the option of adding (or even changing/
288:             * removing) configuration properties for the javascript widget. See <a
289:             * href="http://developer.yahoo.com/yui/calendar/">the widget's
290:             * documentation</a> for the available options. If you want to override/
291:             * remove properties, you should call
292:             * {@link super#setWidgetProperties(Properties)} first. If you don't call
293:             * that, be aware that you will have to call {@link #localize(Map)} manually
294:             * if you like localized strings to be added.
295:             * 
296:             * @param widgetProperties
297:             *            the current widget properties
298:             */
299:            protected void configure(Map widgetProperties) {
300:                widgetProperties.put("close", Boolean.TRUE);
301:                widgetProperties.put("title", "&nbsp;");
302:                // TODO we might want to localize the title nicer in the future, but for
303:                // now, people can override this method or put "title" in the map in
304:                // localize.
305:
306:                // localize date fields
307:                localize(widgetProperties);
308:
309:                Object modelObject = component.getModelObject();
310:                // null and cast check
311:                if (modelObject instanceof  Date) {
312:                    Date date = (Date) modelObject;
313:                    widgetProperties.put("selected", FORMAT_DATE.format(date));
314:                    widgetProperties.put("pagedate", FORMAT_PAGEDATE
315:                            .format(date));
316:                }
317:            }
318:
319:            /**
320:             * @deprecated Please use {@link #configure(Map)} instead.
321:             */
322:            // TODO remove this very ugly named method
323:            protected final void configureWidgetProperties(Map widgetProperties) {
324:                throw new UnsupportedOperationException("");
325:            }
326:
327:            /**
328:             * Filter all empty elements (workaround for {@link DateFormatSymbols}
329:             * returning arrays with empty elements).
330:             * 
331:             * @param array
332:             *            array to filter
333:             * @return filtered array (without null or empty string elements)
334:             */
335:            protected final String[] filterEmpty(String[] array) {
336:                if (array == null) {
337:                    return null;
338:                }
339:                List l = new ArrayList(array.length);
340:                for (int i = 0; i < array.length; i++) {
341:                    if (!Strings.isEmpty(array[i])) {
342:                        l.add(array[i]);
343:                    }
344:                }
345:                return (String[]) l.toArray(new String[l.size()]);
346:            }
347:
348:            /**
349:             * Gets the id of the component that the calendar widget will get attached
350:             * to.
351:             * 
352:             * @return The DOM id of the component
353:             */
354:            protected final String getComponentMarkupId() {
355:                return component.getMarkupId();
356:            }
357:
358:            /**
359:             * @return if true, the base path for all YUI components will be set to
360:             *         /resources/org.apache.wicket.extensions.yui.YuiLib/. True by
361:             *         default.
362:             */
363:            protected boolean getConfigureYUIBasePath() {
364:                return true;
365:            }
366:
367:            /**
368:             * Gets the date pattern to use for putting selected values in the coupled
369:             * component.
370:             * 
371:             * @return The date pattern
372:             */
373:            protected String getDatePattern() {
374:                String format = null;
375:                if (component instanceof  ITextFormatProvider) {
376:                    format = ((ITextFormatProvider) component).getTextFormat();
377:                    // it is possible that components implement ITextFormatProvider but
378:                    // don't provide a format
379:                }
380:
381:                if (format == null) {
382:                    IConverter converter = component
383:                            .getConverter(DateTime.class);
384:                    if (!(converter instanceof  DateConverter)) {
385:                        converter = component.getConverter(Date.class);
386:                    }
387:                    format = ((SimpleDateFormat) ((DateConverter) converter)
388:                            .getDateFormat(component.getLocale())).toPattern();
389:                }
390:
391:                return format;
392:            }
393:
394:            /**
395:             * Gets the escaped DOM id that the calendar widget will get attached to.
396:             * All non word characters (\W) will be removed from the string.
397:             * 
398:             * @return The DOM id of the calendar widget - same as the component's
399:             *         markup id + 'Dp'}
400:             */
401:            protected final String getEscapedComponentMarkupId() {
402:                return component.getMarkupId().replaceAll("\\W", "");
403:            }
404:
405:            /**
406:             * Gets the id of the icon that triggers the popup.
407:             * 
408:             * @return The id of the icon
409:             */
410:            protected final String getIconId() {
411:                return getEscapedComponentMarkupId() + "Icon";
412:            }
413:
414:            /**
415:             * Gets the style of the icon that triggers the popup.
416:             * 
417:             * @return The style of the icon, e.g. 'cursor: point' etc.
418:             */
419:            protected String getIconStyle() {
420:                return "cursor: pointer; border: none;";
421:            }
422:
423:            /**
424:             * Gets the url for the popup button. Users can override to provide their
425:             * own icon URL.
426:             * 
427:             * @return the url to use for the popup button/ icon
428:             */
429:            protected CharSequence getIconUrl() {
430:                return RequestCycle.get().urlFor(
431:                        new ResourceReference(DatePicker.class, "icon1.gif"));
432:            }
433:
434:            /**
435:             * Gets the locale that should be used to configure this widget.
436:             * 
437:             * @return By default the locale of the bound component.
438:             */
439:            protected Locale getLocale() {
440:                return component.getLocale();
441:            }
442:
443:            /**
444:             * Configure the localized strings for the datepicker widget. This
445:             * implementation uses {@link DateFormatSymbols} and some slight string
446:             * manupilation to get the strings for months and week days. It should work
447:             * well for most locales.
448:             * <p>
449:             * This method is called from {@link #configureWidgetProperties(Map)} and
450:             * can be overriden if you want to customize setting up the localized
451:             * strings but are happy with the rest of
452:             * {@link #configureWidgetProperties(Map)}'s behavior. Note that you can
453:             * call (overridable) method {@link #getLocale()} to get the locale that
454:             * should be used for setting up the widget.
455:             * </p>
456:             * <p>
457:             * See YUI Calendar's <a
458:             * href="http://developer.yahoo.com/yui/examples/calendar/germany/1.html">
459:             * German</a> and <a
460:             * href="http://developer.yahoo.com/yui/examples/calendar/japan/1.html">Japanese</a>
461:             * examples for more info.
462:             * </p>
463:             * 
464:             * @param widgetProperties
465:             *            the current widget properties
466:             */
467:            protected void localize(Map widgetProperties) {
468:                DateFormatSymbols dfSymbols = new DateFormatSymbols(getLocale());
469:                setWidgetProperty(widgetProperties, "MONTHS_SHORT",
470:                        filterEmpty(dfSymbols.getShortMonths()));
471:                setWidgetProperty(widgetProperties, "MONTHS_LONG",
472:                        filterEmpty(dfSymbols.getMonths()));
473:                setWidgetProperty(widgetProperties, "WEEKDAYS_1CHAR",
474:                        filterEmpty(substring(dfSymbols.getShortWeekdays(), 1)));
475:                setWidgetProperty(widgetProperties, "WEEKDAYS_SHORT",
476:                        filterEmpty(substring(dfSymbols.getShortWeekdays(), 2)));
477:                setWidgetProperty(widgetProperties, "WEEKDAYS_MEDIUM",
478:                        filterEmpty(dfSymbols.getShortWeekdays()));
479:                setWidgetProperty(widgetProperties, "WEEKDAYS_LONG",
480:                        filterEmpty(dfSymbols.getWeekdays()));
481:            }
482:
483:            /**
484:             * Whether to notify the associated component when a date is selected.
485:             * Notifying is done by calling the associated component's onchange
486:             * Javascript event handler. You can for instance attach an
487:             * {@link AjaxEventBehavior} to that component to get a call back to the
488:             * server. The default is true.
489:             * 
490:             * @return if true, notifies the associated component when a date is
491:             *         selected
492:             */
493:            protected boolean notifyComponentOnDateSelected() {
494:                return true;
495:            }
496:
497:            /**
498:             * Makes a copy of the provided array and for each element copy the
499:             * substring 0..len to the new array
500:             * 
501:             * @param array
502:             *            array to copy from
503:             * @param len
504:             *            size of substring for each element to copy
505:             * @return copy of the array filled with substrings.
506:             */
507:            protected final String[] substring(String[] array, int len) {
508:                if (array != null) {
509:                    String[] copy = new String[array.length];
510:                    for (int i = 0; i < array.length; i++) {
511:                        String el = array[i];
512:                        if (el != null) {
513:                            if (el.length() > len) {
514:                                copy[i] = el.substring(0, len);
515:                            } else {
516:                                copy[i] = el;
517:                            }
518:                        }
519:                    }
520:                    return copy;
521:                }
522:                return null;
523:            }
524:
525:            /**
526:             * Indicates whether plain text is rendered or two select boxes are used to
527:             * allow direct selection of month and year.
528:             * 
529:             * @return <code>true</code> if select boxes should be rendered to allow
530:             *         month and year selection.<br/><code>false</code> to render
531:             *         just plain text.
532:             */
533:            protected boolean enableMonthYearSelection() {
534:                return false;
535:            }
536:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.