Repository: wicket Updated Branches: refs/heads/WICKET-6105-java.time c25e05e31 -> 2f1b9251b
Time field is rewritten to be independent component, build is fixed Project: http://git-wip-us.apache.org/repos/asf/wicket/repo Commit: http://git-wip-us.apache.org/repos/asf/wicket/commit/2f1b9251 Tree: http://git-wip-us.apache.org/repos/asf/wicket/tree/2f1b9251 Diff: http://git-wip-us.apache.org/repos/asf/wicket/diff/2f1b9251 Branch: refs/heads/WICKET-6105-java.time Commit: 2f1b9251b8f1a50a53ac40319eff22f5b7591869 Parents: c25e05e Author: Maxim Solodovnik <[email protected]> Authored: Tue Sep 26 23:47:14 2017 +0700 Committer: Maxim Solodovnik <[email protected]> Committed: Tue Sep 26 23:47:14 2017 +0700 ---------------------------------------------------------------------- wicket-examples/pom.xml | 120 ++--- .../ajax/builtin/modal/ModalContent1Page.html | 12 +- .../ajax/builtin/modal/ModalContent1Page.java | 7 + .../ajax/builtin/modal/ModalContent2Page.java | 1 + .../ajax/builtin/modal/ModalPanel1.java | 19 +- .../ajax/builtin/modal/ModalWindowPage.java | 6 + .../bean/validation/BeanValidationPage.html | 21 +- .../bean/validation/BeanValidationPage.java | 4 +- .../markup/html/form/datetime/DateField.java | 39 +- .../markup/html/form/datetime/DateLabel.java | 2 +- .../html/form/datetime/DateTimeField.html | 5 +- .../html/form/datetime/DateTimeField.java | 387 ++-------------- .../html/form/datetime/LocalDateConverter.java | 2 +- .../html/form/datetime/LocalTimeConverter.java | 103 +++++ .../form/datetime/PatternDateConverter.java | 24 +- .../form/datetime/PatternTimeConverter.java | 85 ++++ .../datetime/PatternZonedDateTimeConverter.java | 97 ++++ .../html/form/datetime/StyleDateConverter.java | 62 +-- .../html/form/datetime/StyleTimeConverter.java | 118 +++++ .../datetime/StyleZonedDateTimeConverter.java | 2 +- .../markup/html/form/datetime/TimeField.html | 25 ++ .../markup/html/form/datetime/TimeField.java | 441 ++++++++++++++++++- .../html/form/datetime/DateConverterTest.java | 4 +- 23 files changed, 1032 insertions(+), 554 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-examples/pom.xml ---------------------------------------------------------------------- diff --git a/wicket-examples/pom.xml b/wicket-examples/pom.xml index b18a14f..0049b0a 100644 --- a/wicket-examples/pom.xml +++ b/wicket-examples/pom.xml @@ -31,32 +31,32 @@ action. </description> - <properties> - <docker-maven-plugin.version>1.0.0</docker-maven-plugin.version> - </properties> + <properties> + <docker-maven-plugin.version>1.0.0</docker-maven-plugin.version> + </properties> <dependencyManagement> - <dependencies> - <dependency> - <groupId>com.github.axet</groupId> - <artifactId>kaptcha</artifactId> - <version>0.0.9</version> - </dependency> - <dependency> - <groupId>com.github.cage</groupId> - <artifactId>cage</artifactId> - <version>1.0</version> - </dependency> - <dependency> - <groupId>org.codelibs</groupId> - <artifactId>jhighlight</artifactId> - <version>1.0.3</version> - <exclusions> - <exclusion> - <groupId>javax.servlet</groupId> - <artifactId>servlet-api</artifactId> - </exclusion> - </exclusions> + <dependencies> + <dependency> + <groupId>com.github.axet</groupId> + <artifactId>kaptcha</artifactId> + <version>0.0.9</version> + </dependency> + <dependency> + <groupId>com.github.cage</groupId> + <artifactId>cage</artifactId> + <version>1.0</version> + </dependency> + <dependency> + <groupId>org.codelibs</groupId> + <artifactId>jhighlight</artifactId> + <version>1.0.3</version> + <exclusions> + <exclusion> + <groupId>javax.servlet</groupId> + <artifactId>servlet-api</artifactId> + </exclusion> + </exclusions> </dependency> </dependencies> </dependencyManagement> @@ -142,10 +142,10 @@ <groupId>org.apache.wicket</groupId> <artifactId>wicket-velocity</artifactId> </dependency> - <dependency> - <groupId>org.apache.wicket</groupId> - <artifactId>wicket-native-websocket-javax</artifactId> - </dependency> + <dependency> + <groupId>org.apache.wicket</groupId> + <artifactId>wicket-native-websocket-javax</artifactId> + </dependency> <dependency> <groupId>org.codelibs</groupId> <artifactId>jhighlight</artifactId> @@ -235,38 +235,38 @@ </plugins> <pluginManagement> <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-javadoc-plugin</artifactId> - <configuration> - <skip>true</skip> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-war-plugin</artifactId> - <configuration> - <!-- include the manifest entries so that we can emit the version of the examples. --> - <archive> - <manifest> - <addDefaultImplementationEntries>true</addDefaultImplementationEntries> - <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> - </manifest> - </archive> - </configuration> - </plugin> - <plugin> - <groupId>org.mortbay.jetty</groupId> - <artifactId>jetty-maven-plugin</artifactId> - <version>${jetty.version}</version> - <dependencies> - <dependency> - <groupId>javax.validation</groupId> - <artifactId>validation-api</artifactId> - <version>1.1.0.Final</version> - </dependency> - </dependencies> - </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <configuration> + <skip>true</skip> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-war-plugin</artifactId> + <configuration> + <!-- include the manifest entries so that we can emit the version of the examples. --> + <archive> + <manifest> + <addDefaultImplementationEntries>true</addDefaultImplementationEntries> + <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries> + </manifest> + </archive> + </configuration> + </plugin> + <plugin> + <groupId>org.mortbay.jetty</groupId> + <artifactId>jetty-maven-plugin</artifactId> + <version>${jetty.version}</version> + <dependencies> + <dependency> + <groupId>javax.validation</groupId> + <artifactId>validation-api</artifactId> + <version>1.1.0.Final</version> + </dependency> + </dependencies> + </plugin> </plugins> </pluginManagement> </build> http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.html ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.html b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.html index c5e8099..528940e 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.html +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.html @@ -2,11 +2,11 @@ <html xmlns:wicket="http://wicket.apache.org"> <head> <title>This is modal window</title> - <style type="text/css"> + <style type="text/css"> body { font-family: verdana, sans-serif; font-size: 82%; - background-color: white; + background-color: white; } </style> </head> @@ -18,13 +18,11 @@ </p> <p> <div wicket:id="modal"></div> - <a wicket:id="open">Open another modal dialog</a> + <a wicket:id="open">Open another modal dialog</a> </p> - <p> - <div>An example of a component that uses header contributions</div> - <div wicket:id="dateTimeField" /> + <div>An example of a component that uses header contributions</div> + <div wicket:id="dateTimeField" /> </p> - </body> </html> \ No newline at end of file http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.java b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.java index 4111a46..5c252e4 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent1Page.java @@ -30,6 +30,7 @@ import org.apache.wicket.markup.html.WebPage; */ public class ModalContent1Page extends WebPage { + private static final long serialVersionUID = 1L; /** * @@ -40,6 +41,8 @@ public class ModalContent1Page extends WebPage { add(new AjaxLink<Void>("closeOK") { + private static final long serialVersionUID = 1L; + @Override public void onClick(AjaxRequestTarget target) { @@ -51,6 +54,8 @@ public class ModalContent1Page extends WebPage add(new AjaxLink<Void>("closeCancel") { + private static final long serialVersionUID = 1L; + @Override public void onClick(AjaxRequestTarget target) { @@ -85,6 +90,8 @@ public class ModalContent1Page extends WebPage add(new AjaxLink<Void>("open") { + private static final long serialVersionUID = 1L; + @Override public void onClick(AjaxRequestTarget target) { http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent2Page.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent2Page.java b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent2Page.java index 0189a93..4b668ac 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent2Page.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalContent2Page.java @@ -28,6 +28,7 @@ import org.apache.wicket.markup.html.WebPage; */ public class ModalContent2Page extends WebPage { + private static final long serialVersionUID = 1L; /** * @param window http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalPanel1.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalPanel1.java b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalPanel1.java index ec7bae6..3a9389a 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalPanel1.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalPanel1.java @@ -16,8 +16,6 @@ */ package org.apache.wicket.examples.ajax.builtin.modal; -import java.util.Map; - import org.apache.wicket.extensions.markup.html.form.datetime.DateTimeField; import org.apache.wicket.markup.html.panel.Panel; @@ -26,6 +24,7 @@ import org.apache.wicket.markup.html.panel.Panel; */ public class ModalPanel1 extends Panel { + private static final long serialVersionUID = 1L; /** * @param id @@ -33,20 +32,6 @@ public class ModalPanel1 extends Panel public ModalPanel1(String id) { super(id); - - add(new DateTimeField("dateTimeField") - { - /** - * @see DateTimeField#configure(java.util.Map) - */ - @Override - protected void configure(Map<String, Object> widgetProperties) - { - super.configure(widgetProperties); - // IE 6 breaks layout with iframe - is that a YUI bug? - widgetProperties.put("iframe", false); - } - }); + add(new DateTimeField("dateTimeField")); } - } http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalWindowPage.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalWindowPage.java b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalWindowPage.java index 7de1620..f8376ff 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalWindowPage.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/ajax/builtin/modal/ModalWindowPage.java @@ -29,6 +29,8 @@ import org.apache.wicket.model.PropertyModel; */ public class ModalWindowPage extends BasePage { + private static final long serialVersionUID = 1L; + public ModalWindowPage() { final Label result; @@ -53,6 +55,8 @@ public class ModalWindowPage extends BasePage add(new AjaxLink<Void>("showModal1") { + private static final long serialVersionUID = 1L; + @Override public void onClick(AjaxRequestTarget target) { @@ -80,6 +84,8 @@ public class ModalWindowPage extends BasePage add(new AjaxLink<Void>("showModal2") { + private static final long serialVersionUID = 1L; + @Override public void onClick(AjaxRequestTarget target) { http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.html ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.html b/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.html index a459fd9..db04a1c 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.html +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.html @@ -5,15 +5,17 @@ <style> .note { font-size:.8em; } .required {font-weight: bold;} + table {border-collapse: collapse; border-spacing: 0;} + th, td {padding: 4px;} </style> </head> <body> - <span wicket:id="mainNavigation" /> + <span wicket:id="mainNavigation"></span> <div wicket:id="feedbackErrors"></div> - + <form wicket:id="form" novalidate="novalidate"> - <table cellspacing="0" cellpadding="4"> + <table style="border-collapse: collapse; border-spacing: 0;"> <tr> <td><label wicket:for="name"><wicket:label>Name</wicket:label></label></td> <td><input wicket:id="name" type="text" size="30"/></td> @@ -35,11 +37,12 @@ <td><pre class="note">m/d/yyyy field with @Past</pre></td> </tr> <tr> - <td><label wicket:for="password"><wicket:label>Password</wicket:label></label></td> - <td><input wicket:id="password" type="text" size="10"/></td> - <td><pre class="note">Custom constraint @ValidPassword with custom message bundles.<br/>A valid password must contain only alphanumeric chars and at least two digits.</pre> - </td> - </tr> + <td><label wicket:for="password"><wicket:label>Password</wicket:label></label></td> + <td><input wicket:id="password" type="text" size="10"/></td> + <td> + <pre class="note">Custom constraint @ValidPassword with custom message bundles.<br/>A valid password must contain only alphanumeric chars and at least two digits.</pre> + </td> + </tr> <tr> <td></td> <td> @@ -49,6 +52,6 @@ </tr> </table> </form> - <div wicket:id="feedbackSuccess"></div> + <div wicket:id="feedbackSuccess"></div> </body> </html> http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.java ---------------------------------------------------------------------- diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.java b/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.java index b69b019..e1eb59d 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/bean/validation/BeanValidationPage.java @@ -18,7 +18,7 @@ package org.apache.wicket.examples.bean.validation; import org.apache.wicket.bean.validation.PropertyValidator; import org.apache.wicket.extensions.markup.html.form.datetime.DateField; -import org.apache.wicket.extensions.markup.html.form.datetime.StyleZonedDateTimeConverter; +import org.apache.wicket.extensions.markup.html.form.datetime.StyleDateConverter; import org.apache.wicket.examples.WicketExamplePage; import org.apache.wicket.feedback.ExactLevelFeedbackMessageFilter; import org.apache.wicket.feedback.FeedbackMessage; @@ -53,7 +53,7 @@ public class BeanValidationPage extends WicketExamplePage form.add(new TextField<>("phone", new PropertyModel<String>(this, "person.phone")).add(new PropertyValidator<>())); form.add(new TextField<>("email", new PropertyModel<String>(this, "person.email")).add(new PropertyValidator<>())); form.add(new DateField("birthdate", new PropertyModel<>(this, "person.birthdate"), - new StyleZonedDateTimeConverter("S-", true)).add(new PropertyValidator<>())); + new StyleDateConverter("S-")).add(new PropertyValidator<>())); form.add(new TextField<>("password", new PropertyModel<String>(this, "person.password")).add(new PropertyValidator<>())); add(new FeedbackPanel("feedbackSuccess", new ExactLevelFeedbackMessageFilter(FeedbackMessage.INFO))); http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateField.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateField.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateField.java index d4b5ef4..88d2637 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateField.java +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateField.java @@ -51,7 +51,7 @@ public class DateField extends TextField<LocalDate> implements ITextFormatProvid private static final long serialVersionUID = 1L; /** - * Creates a new DateTextField defaulting to using a short date pattern + * Creates a new DateField defaulting to using a short date pattern * * @param id * The id of the text field @@ -60,22 +60,22 @@ public class DateField extends TextField<LocalDate> implements ITextFormatProvid * @param datePattern * The pattern to use. Must be not null. See {@link SimpleDateFormat} for available * patterns. - * @return DateTextField + * @return DateField */ public static DateField forDatePattern(String id, IModel<LocalDate> model, String datePattern) { - return new DateField(id, model, new PatternDateConverter(datePattern, true)); + return new DateField(id, model, new PatternDateConverter(datePattern)); } /** - * Creates a new DateTextField defaulting to using a short date pattern + * Creates a new DateField defaulting to using a short date pattern * * @param id * The id of the text field * @param datePattern * The pattern to use. Must be not null. See {@link SimpleDateFormat} for available * patterns. - * @return DateTextField + * @return DateField */ public static DateField forDatePattern(String id, String datePattern) { @@ -83,7 +83,7 @@ public class DateField extends TextField<LocalDate> implements ITextFormatProvid } /** - * Creates a new DateTextField using the provided date style. + * Creates a new DateField using the provided date style. * * @param id * The id of the text field @@ -94,16 +94,15 @@ public class DateField extends TextField<LocalDate> implements ITextFormatProvid * is the time style. Specify a character of 'S' for short style, 'M' for medium, 'L' * for long, and 'F' for full. A date or time may be ommitted by specifying a style * character '-'. See {@link org.joda.time.DateTimeFormat#forStyle(String)}. - * @return DateTextField + * @return DateField */ public static DateField forDateStyle(String id, IModel<LocalDate> model, String dateStyle) { - FormatStyle dateFormatStyle = parseFormatStyle(dateStyle.charAt(0)); - return new DateField(id, model, new StyleZonedDateTimeConverter(dateStyle, null, false)); + return new DateField(id, model, new StyleDateConverter(dateStyle)); } /** - * Creates a new DateTextField using the provided date style. + * Creates a new DateField using the provided date style. * * @param id * The id of the text field @@ -112,7 +111,7 @@ public class DateField extends TextField<LocalDate> implements ITextFormatProvid * is the time style. Specify a character of 'S' for short style, 'M' for medium, 'L' * for long, and 'F' for full. A date or time may be ommitted by specifying a style * character '-'. See {@link org.joda.time.DateTimeFormat#forStyle(String)}. - * @return DateTextField + * @return DateField */ public static DateField forDateStyle(String id, String dateStyle) { @@ -120,11 +119,11 @@ public class DateField extends TextField<LocalDate> implements ITextFormatProvid } /** - * Creates a new DateTextField defaulting to using a short date pattern + * Creates a new DateField defaulting to using a short date pattern * * @param id * The id of the text field - * @return DateTextField + * @return DateField */ public static DateField forShortStyle(String id) { @@ -132,27 +131,27 @@ public class DateField extends TextField<LocalDate> implements ITextFormatProvid } /** - * Creates a new DateTextField defaulting to using a short date pattern + * Creates a new DateField defaulting to using a short date pattern * * @param id * The id of the text field * @param model * The model - * @return DateTextField + * @return DateField */ public static DateField forShortStyle(String id, IModel<LocalDate> model) { - return new DateField(id, model, new StyleZonedDateTimeConverter(false)); + return new DateField(id, model, new StyleDateConverter()); } /** - * Creates a new DateTextField using the provided converter. + * Creates a new DateField using the provided converter. * * @param id * The id of the text field * @param converter * the date converter - * @return DateTextField + * @return DateField */ public static DateField withConverter(String id, IDateConverter<LocalDate> converter) { @@ -160,7 +159,7 @@ public class DateField extends TextField<LocalDate> implements ITextFormatProvid } /** - * Creates a new DateTextField using the provided converter. + * Creates a new DateField using the provided converter. * * @param id * The id of the text field @@ -168,7 +167,7 @@ public class DateField extends TextField<LocalDate> implements ITextFormatProvid * The model * @param converter * the date converter - * @return DateTextField + * @return DateField */ public static DateField withConverter(String id, IModel<LocalDate> model, IDateConverter<LocalDate> converter) { http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateLabel.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateLabel.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateLabel.java index 957e53e..1f8531a 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateLabel.java +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateLabel.java @@ -64,7 +64,7 @@ public class DateLabel extends Label implements IGenericComponent<LocalDate, Dat */ public static DateLabel forDatePattern(String id, IModel<LocalDate> model, String datePattern) { - return new DateLabel(id, model, new PatternDateConverter(datePattern, true)); + return new DateLabel(id, model, new PatternZonedDateTimeConverter(datePattern, true)); } /** http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.html ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.html b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.html index 8bcd43b..d92f2ce 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.html +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.html @@ -18,9 +18,6 @@ <wicket:panel xmlns:wicket="http://wicket.apache.org"> <span style="white-space: nowrap;"> <input type="text" wicket:id="date" size="12" /> - <input type="text" wicket:id="hours" size="2" maxlength="2" /> - <span wicket:id="hoursSeparator"> :</span> - <input type="text" wicket:id="minutes" size="2" maxlength="2" /> - <select wicket:id="amOrPmChoice"></select> + <span wicket:id="time" /> </span> </wicket:panel> http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.java index eff009a..200129f 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.java +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/DateTimeField.java @@ -16,33 +16,21 @@ */ package org.apache.wicket.extensions.markup.html.form.datetime; -import java.text.DecimalFormat; -import java.text.NumberFormat; import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.temporal.ChronoField; -import java.util.Arrays; -import java.util.Calendar; import java.util.Date; import java.util.Locale; -import java.util.Map; import java.util.TimeZone; import org.apache.wicket.Session; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.core.request.ClientInfo; -import org.apache.wicket.markup.html.WebMarkupContainer; -import org.apache.wicket.markup.html.form.DropDownChoice; import org.apache.wicket.markup.html.form.FormComponentPanel; -import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.IModel; -import org.apache.wicket.model.Model; import org.apache.wicket.protocol.http.request.WebClientInfo; -import org.apache.wicket.util.convert.IConverter; -import org.apache.wicket.util.convert.converter.IntegerConverter; -import org.apache.wicket.validation.validator.RangeValidator; /** * Works on a {@link java.time.ZonedDateTime} object. Displays a date field and a DatePicker, a field @@ -77,64 +65,18 @@ import org.apache.wicket.validation.validator.RangeValidator; */ public class DateTimeField extends FormComponentPanel<ZonedDateTime> { - /** - * Enumerated type for different ways of handling the render part of requests. - */ - public enum AM_PM { - /** */ - AM("AM"), - - /** */ - PM("PM"); - - private final String value; - - AM_PM(final String name) - { - value = name; - } - - @Override - public String toString() - { - return value; - } - } - private static final long serialVersionUID = 1L; // Component-IDs protected static final String DATE = "date"; - protected static final String HOURS = "hours"; - protected static final String MINUTES = "minutes"; - protected static final String AM_OR_PM_CHOICE = "amOrPmChoice"; - - // PropertyModel string to access getAmOrPm - private static final String AM_OR_PM = "amOrPm"; - - private static final IConverter<Integer> MINUTES_CONVERTER = new IntegerConverter() { - private static final long serialVersionUID = 1L; - - protected NumberFormat newNumberFormat(Locale locale) { - return new DecimalFormat("00"); - } - }; - - // The dropdown list for AM/PM and it's associated model object - private DropDownChoice<AM_PM> amOrPmChoice; - private AM_PM amOrPm = AM_PM.AM; + protected static final String TIME = "time"; // The date TextField and it's associated model object // Note that any time information in date will be ignored private DateField dateField; + private TimeField timeField; private ZonedDateTime dateTime = ZonedDateTime.now(); - // The TextField for "hours" and it's associated model object - private TextField<Integer> hoursField; - - // The TextField for "minutes" and it's associated model object - private TextField<Integer> minutesField; - /** * Construct. * @@ -156,121 +98,29 @@ public class DateTimeField extends FormComponentPanel<ZonedDateTime> super(id, model); // Sets the type that will be used when updating the model for this component. - setType(Date.class); + setType(ZonedDateTime.class); // Create and add the date TextField - add(dateField = newDateTextField(DATE, new DateModel())); - - // Add a date picker to the date TextField -// dateField.add(newDatePicker()); - - // Create and add the "hours" TextField - add(hoursField = newHoursTextField(HOURS, new HoursModel(), Integer.class)); - - // Create and add the "minutes" TextField - add(minutesField = newMinutesTextField(MINUTES, new MinutesModel(), Integer.class)); - - // Create and add the "AM/PM" Listbox - add(amOrPmChoice = new DropDownChoice<>(AM_OR_PM_CHOICE, new AmPmModel(), Arrays.asList(AM_PM.values()))); - - add(new WebMarkupContainer("hoursSeparator") - { - private static final long serialVersionUID = 1L; - - @Override - public boolean isVisible() - { - return minutesField.determineVisibility(); - } - }); - } - - /** - * create a new {@link TextField} instance for hours to be added to this panel. - * - * @param id - * the component id - * @param model - * model that should be used by the {@link TextField} - * @param type - * the type of the text field - * @return a new text field instance - */ - protected TextField<Integer> newHoursTextField(final String id, IModel<Integer> model, Class<Integer> type) { - TextField<Integer> hoursTextField = new TextField<>(id, model, type); - hoursTextField.add(getMaximumHours() == 24 ? RangeValidator.range(0, 23) : RangeValidator - .range(1, 12)); - hoursTextField.setLabel(new Model<>(HOURS)); - return hoursTextField; - } - - /** - * create a new {@link TextField} instance for minutes to be added to this panel. - * - * @param id - * the component id - * @param model - * model that should be used by the {@link TextField} - * @param type - * the type of the text field - * @return a new text field instance - */ - protected TextField<Integer> newMinutesTextField(final String id, IModel<Integer> model, - Class<Integer> type) - { - TextField<Integer> minutesField = new TextField<Integer>(id, model, type) - { - private static final long serialVersionUID = 1L; - - @Override - protected IConverter<?> createConverter(Class<?> type) - { - if (Integer.class.isAssignableFrom(type)) - { - return MINUTES_CONVERTER; - } - return null; - } - }; - minutesField.add(new RangeValidator<>(0, 59)); - minutesField.setLabel(new Model<>(MINUTES)); - return minutesField; + add(dateField = newDateField(DATE, new DateModel())); + add(timeField = newTimeField(TIME, new TimeModel())); } /** * * @return The date TextField */ - protected final DateField getDateTextField() + protected final DateField getDateField() { return dateField; } /** - * Gets the amOrPm model object of the drop down choice. * - * @return amOrPm - * - * @deprecated valid during rendering only - */ - public final AM_PM getAmOrPm() - { - return amOrPm; - } - - /** - * Gives overriding classes the option of adding (or even changing/ removing) configuration - * properties for the javascript widget. See <a - * href="http://developer.yahoo.com/yui/calendar/">the widget's documentation</a> for the - * available options. If you want to override/ remove properties, you should call - * super.configure(properties) first. If you don't call that, be aware that you will have to - * call {@link #configure(java.util.Map)} manually if you like localized strings to be added. - * - * @param widgetProperties - * the current widget properties + * @return The date TextField */ - protected void configure(Map<String, Object> widgetProperties) + protected final TimeField getTimeField() { + return timeField; } @Override @@ -278,18 +128,7 @@ public class DateTimeField extends FormComponentPanel<ZonedDateTime> { // since we override convertInput, we can let this method return a value // that is just suitable for error reporting - return dateField.getInput() + ", " + hoursField.getInput() + ":" + minutesField.getInput(); - } - - /** - * Sets the amOrPm model object associated with the drop down choice. - * - * @param amOrPm - * amOrPm - */ - public final void setAmOrPm(final AM_PM amOrPm) - { - this.amOrPm = amOrPm; + return String.format("%s, %s", dateField.getInput(), timeField.getInput()); } /** @@ -324,27 +163,16 @@ public class DateTimeField extends FormComponentPanel<ZonedDateTime> try { // Get the converted input values - LocalDate dateFieldInput = dateField.getConvertedInput(); - Integer hoursInput = hoursField.getConvertedInput(); - Integer minutesInput = minutesField.getConvertedInput(); - AM_PM amOrPmInput = amOrPmChoice.getConvertedInput(); + LocalDate localDate = dateField.getConvertedInput(); - if (dateFieldInput == null) + if (localDate == null) { return; } // Use the input to create a date object with proper timezone - LocalTime localTime = LocalTime.of(hoursInput, minutesInput); - ZonedDateTime date = ZonedDateTime.of(dateFieldInput, localTime, getClientTimeZone()); - - // Adjust for halfday if needed - if (use12HourFormat()) - { - int halfday = (amOrPmInput == AM_PM.PM ? 1 : 0); - date = date.with(ChronoField.AMPM_OF_DAY, halfday); -// date = date.with(ChronoField.HOUR_OF_AMPM, hours % 12); - } + LocalTime localTime = timeField.getConvertedInput(); + ZonedDateTime date = ZonedDateTime.of(localDate, localTime, getClientTimeZone()); // The date will be in the server's timezone setConvertedInput(date); @@ -357,39 +185,31 @@ public class DateTimeField extends FormComponentPanel<ZonedDateTime> } /** - * A factory method for the DateTextField's model object. - * - * @return any specialization of java.util.Date - */ - protected LocalDate newDateInstance() - { - return LocalDate.now(); - } - - /** - * A factory method for the DateTextField's model object. + * create a new {@link DateField} instance to be added to this panel. * - * @param time - * the time in milliseconds - * @return any specialization of java.util.Date + * @param id + * the component id + * @param dateFieldModel + * model that should be used by the {@link DateField} + * @return a new date text field instance */ - protected Date newDateInstance(long time) + protected DateField newDateField(String id, IModel<LocalDate> dateFieldModel) { - return new Date(time); + return DateField.forShortStyle(id, dateFieldModel); } /** - * create a new {@link DateField} instance to be added to this panel. + * create a new {@link TimeField} instance to be added to this panel. * * @param id * the component id - * @param dateFieldModel - * model that should be used by the {@link DateField} - * @return a new date text field instance + * @param timeFieldModel + * model that should be used by the {@link TimeField} + * @return a new time text field instance */ - protected DateField newDateTextField(String id, IModel<LocalDate> dateFieldModel) + protected TimeField newTimeField(String id, IModel<LocalTime> timeFieldModel) { - return DateField.forShortStyle(id, dateFieldModel); + return TimeField.forShortStyle(id, timeFieldModel); } /** @@ -399,11 +219,7 @@ public class DateTimeField extends FormComponentPanel<ZonedDateTime> protected void onBeforeRender() { dateField.setRequired(isRequired()); - hoursField.setRequired(isRequired()); - minutesField.setRequired(isRequired()); - - boolean use12HourFormat = use12HourFormat(); - amOrPmChoice.setVisible(use12HourFormat); + timeField.setRequired(isRequired()); ZonedDateTime modelObject = getModelObject(); if (modelObject == null) @@ -423,93 +239,6 @@ public class DateTimeField extends FormComponentPanel<ZonedDateTime> super.onBeforeRender(); } - /** - * Change a date in another timezone - * - * @param date - * The input date. - * @param zone - * The target timezone. - * @return A new converted date. - */ - public static Date changeTimeZone(Date date, TimeZone zone) - { - Calendar first = Calendar.getInstance(zone); - first.setTimeInMillis(date.getTime()); - - Calendar output = Calendar.getInstance(); - output.set(Calendar.YEAR, first.get(Calendar.YEAR)); - output.set(Calendar.MONTH, first.get(Calendar.MONTH)); - output.set(Calendar.DAY_OF_MONTH, first.get(Calendar.DAY_OF_MONTH)); - output.set(Calendar.HOUR_OF_DAY, first.get(Calendar.HOUR_OF_DAY)); - output.set(Calendar.MINUTE, first.get(Calendar.MINUTE)); - output.set(Calendar.SECOND, first.get(Calendar.SECOND)); - output.set(Calendar.MILLISECOND, first.get(Calendar.MILLISECOND)); - - return output.getTime(); - } - - /** - * Checks whether the current {@link Locale} uses the 12h or 24h time format. This method can be - * overridden to e.g. always use 24h format. - * - * @return true, if the current {@link Locale} uses the 12h format.<br/> - * false, otherwise - */ - protected boolean use12HourFormat() - { - // TODO Fix ! - return false; -// String pattern = DateTimeFormat.patternForStyle("-S", getLocale()); -// return pattern.indexOf('a') != -1 || pattern.indexOf('h') != -1 -// || pattern.indexOf('K') != -1; - } - - /** - * @return either 12 or 24, depending on the hour format of the current {@link Locale} - */ - private int getMaximumHours() - { - return getMaximumHours(use12HourFormat()); - } - - /** - * Convenience method (mainly for optimization purposes), in case {@link #use12HourFormat()} has - * already been stored in a local variable and thus doesn't need to be computed again. - * - * @param use12HourFormat - * the hour format to use - * @return either 12 or 24, depending on the parameter <code>use12HourFormat</code> - */ - private int getMaximumHours(boolean use12HourFormat) - { - return use12HourFormat ? 12 : 24; - } -// -// /** -// * The DatePicker that gets added to the DateTimeField component. Users may override this method -// * with a DatePicker of their choice. -// * -// * @return a new {@link DatePicker} instance -// */ -// protected DatePicker newDatePicker() -// { -// return new DatePicker() -// { -// private static final long serialVersionUID = 1L; -// -// @Override -// protected void configure(final Map<String, Object> widgetProperties, -// final IHeaderResponse response, final Map<String, Object> initVariables) -// { -// super.configure(widgetProperties, response, initVariables); -// -// DateTimeField.this.configure(widgetProperties); -// } -// }; -// } - - protected class DateModel implements IModel<LocalDate> { private static final long serialVersionUID = 1L; @@ -534,42 +263,21 @@ public class DateTimeField extends FormComponentPanel<ZonedDateTime> } } - protected class HoursModel implements IModel<Integer> - { - private static final long serialVersionUID = 1L; - - @Override - public Integer getObject() - { - return dateTime.getHour(); - } - - @Override - public void setObject(Integer hour) - { - dateTime = dateTime.with(ChronoField.HOUR_OF_DAY, hour); - } - - @Override - public void detach() - { - } - } - - protected class MinutesModel implements IModel<Integer> + protected class TimeModel implements IModel<LocalTime> { private static final long serialVersionUID = 1L; @Override - public Integer getObject() + public LocalTime getObject() { - return dateTime.getMinute(); + return dateTime.toLocalTime(); } @Override - public void setObject(Integer minute) + public void setObject(LocalTime time) { - dateTime = dateTime.with(ChronoField.MINUTE_OF_HOUR, minute); + dateTime = dateTime.with(ChronoField.HOUR_OF_DAY, time.getHour()); + dateTime = dateTime.with(ChronoField.MINUTE_OF_HOUR, time.getMinute()); } @Override @@ -577,29 +285,4 @@ public class DateTimeField extends FormComponentPanel<ZonedDateTime> { } } - - protected class AmPmModel implements IModel<AM_PM> - { - private static final long serialVersionUID = 1L; - - @Override - public AM_PM getObject() - { - int i = dateTime.get(ChronoField.AMPM_OF_DAY); - return i == 0 ? AM_PM.AM : AM_PM.PM; - } - - @Override - public void setObject(AM_PM amPm) - { - int i = AM_PM.AM == amPm ? 0 : 1; - dateTime = dateTime.with(ChronoField.AMPM_OF_DAY, i); - } - - @Override - public void detach() - { - } - } - } http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/LocalDateConverter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/LocalDateConverter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/LocalDateConverter.java index 9306d8d..28554bd 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/LocalDateConverter.java +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/LocalDateConverter.java @@ -26,7 +26,7 @@ import org.apache.wicket.util.string.Strings; /** - * Base class for Joda Time based date converters. It contains the logic to parse and format, + * Base class for java.time based date converters. It contains the logic to parse and format, * optionally taking the time zone difference between clients and the server into account. * <p> * Converters of this class are best suited for per-component use. http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/LocalTimeConverter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/LocalTimeConverter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/LocalTimeConverter.java new file mode 100644 index 0000000..a10a662 --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/LocalTimeConverter.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.form.datetime; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +import org.apache.wicket.util.convert.ConversionException; +import org.apache.wicket.util.lang.Args; +import org.apache.wicket.util.string.Strings; + + +/** + * Base class for java.time based date converters. It contains the logic to parse and format, + * optionally taking the time zone difference between clients and the server into account. + * <p> + * Converters of this class are best suited for per-component use. + * </p> + * + * @author eelcohillenius + */ +public abstract class LocalTimeConverter implements IDateConverter<LocalTime> +{ + private static final long serialVersionUID = 1L; + + public LocalTime convertToObject(String value, DateTimeFormatter format, Locale locale) { + try + { + // parse date retaining the time of the submission + return LocalTime.parse(value, format); + } + catch (RuntimeException e) + { + throw newConversionException(e, locale); + } + } + + @Override + public LocalTime convertToObject(String value, Locale locale) + { + if (Strings.isEmpty(value)) + { + return null; + } + + DateTimeFormatter format = getFormat(locale); + Args.notNull(format, "format"); + + return convertToObject(value, format, locale); + } + + /** + * Creates a ConversionException and sets additional context information to it. + * + * @param cause + * - {@link RuntimeException} cause + * @param locale + * - {@link Locale} used to set 'format' variable with localized pattern + * @return {@link ConversionException} + */ + ConversionException newConversionException(RuntimeException cause, Locale locale) + { + return new ConversionException(cause) + .setVariable("format", getPattern(locale)); + } + + @Override + public String convertToString(LocalTime time, Locale locale) + { + DateTimeFormatter format = getFormat(locale); + return format.format(time); + } + + /** + * @param locale + * The locale used to convert the value + * @return Gets the pattern that is used for printing and parsing + */ + public abstract String getPattern(Locale locale); + + /** + * @param locale + * The locale used to convert the value + * + * @return formatter The formatter for the current conversion + */ + public abstract DateTimeFormatter getFormat(Locale locale); +} http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternDateConverter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternDateConverter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternDateConverter.java index e2b714f..54ea179 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternDateConverter.java +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternDateConverter.java @@ -24,7 +24,7 @@ import org.apache.wicket.util.lang.Args; /** - * Date converter that uses Joda Time and can be configured to take the time zone difference between + * Date converter that uses javax.time and can be configured to take the time zone difference between * clients and server into account. This converter is hard coded to use the provided custom date * pattern, no matter what current locale is used. See {@link SimpleDateFormat} for available * patterns. @@ -33,15 +33,14 @@ import org.apache.wicket.util.lang.Args; * </p> * * @see SimpleDateFormat - * @see StyleZonedDateTimeConverter + * @see StyleDateConverter * @see org.apache.wicket.extensions.markup.html.form.DateTextField - * @see java.time.ZonedDateTime + * @see java.time.LocalDate * @see DateTimeFormatter - * @see java.time.ZoneId * * @author eelcohillenius */ -public class PatternDateConverter extends ZonedDateTimeConverter +public class PatternDateConverter extends LocalDateConverter { private static final long serialVersionUID = 1L; @@ -51,27 +50,16 @@ public class PatternDateConverter extends ZonedDateTimeConverter /** * Construct. - * </p> - * When applyTimeZoneDifference is true, the current time is applied on the parsed date, and the - * date will be corrected for the time zone difference between the server and the client. For - * instance, if I'm in Seattle and the server I'm working on is in Amsterdam, the server is 9 - * hours ahead. So, if I'm inputting say 12/24 at a couple of hours before midnight, at the - * server it is already 12/25. If this boolean is true, it will be transformed to 12/25, while - * the client sees 12/24. - * </p> * * @param datePattern * The pattern to use. Must be not null. See {@link SimpleDateFormat} for available * patterns. - * @param applyTimeZoneDifference - * whether to apply the difference in time zones between client and server * @throws IllegalArgumentException * in case the date pattern is null */ - public PatternDateConverter(String datePattern, boolean applyTimeZoneDifference) + public PatternDateConverter(String datePattern) { - - super(applyTimeZoneDifference); + super(); this.datePattern = Args.notNull(datePattern, "datePattern"); } http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternTimeConverter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternTimeConverter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternTimeConverter.java new file mode 100644 index 0000000..021f500 --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternTimeConverter.java @@ -0,0 +1,85 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.form.datetime; + +import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +import org.apache.wicket.util.lang.Args; + + +/** + * Date converter that uses javax.time and can be configured to take the time zone difference between + * clients and server into account. This converter is hard coded to use the provided custom date + * pattern, no matter what current locale is used. See {@link SimpleDateFormat} for available + * patterns. + * <p> + * This converter is especially suited on a per-component base. + * </p> + * + * @see SimpleDateFormat + * @see StyleDateConverter + * @see org.apache.wicket.extensions.markup.html.form.DateTextField + * @see java.time.LocalTime + * @see DateTimeFormatter + * + * @author eelcohillenius + */ +public class PatternTimeConverter extends LocalTimeConverter +{ + + private static final long serialVersionUID = 1L; + + /** pattern to use. */ + private final String timePattern; + + /** + * Construct. + * + * @param timePattern + * The pattern to use. Must be not null. See {@link SimpleDateFormat} for available + * patterns. + * @throws IllegalArgumentException + * in case the date pattern is null + */ + public PatternTimeConverter(String timePattern) + { + super(); + this.timePattern = Args.notNull(timePattern, "timePattern"); + } + + /** + * Gets the optional date pattern. + * + * @return datePattern + */ + @Override + public final String getPattern(Locale locale) + { + return timePattern; + } + + /** + * @return formatter The formatter for the current conversion + */ + @Override + public DateTimeFormatter getFormat(Locale locale) + { + return DateTimeFormatter.ofPattern(timePattern).withLocale(locale); + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternZonedDateTimeConverter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternZonedDateTimeConverter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternZonedDateTimeConverter.java new file mode 100644 index 0000000..c432d90 --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/PatternZonedDateTimeConverter.java @@ -0,0 +1,97 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.form.datetime; + +import java.text.SimpleDateFormat; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +import org.apache.wicket.util.lang.Args; + + +/** + * Date converter that uses javax.time and can be configured to take the time zone difference between + * clients and server into account. This converter is hard coded to use the provided custom date + * pattern, no matter what current locale is used. See {@link SimpleDateFormat} for available + * patterns. + * <p> + * This converter is especially suited on a per-component base. + * </p> + * + * @see SimpleDateFormat + * @see StyleZonedDateTimeConverter + * @see org.apache.wicket.extensions.markup.html.form.DateTextField + * @see java.time.ZonedDateTime + * @see DateTimeFormatter + * @see java.time.ZoneId + * + * @author eelcohillenius + */ +public class PatternZonedDateTimeConverter extends ZonedDateTimeConverter +{ + + private static final long serialVersionUID = 1L; + + /** pattern to use. */ + private final String datePattern; + + /** + * Construct. + * </p> + * When applyTimeZoneDifference is true, the current time is applied on the parsed date, and the + * date will be corrected for the time zone difference between the server and the client. For + * instance, if I'm in Seattle and the server I'm working on is in Amsterdam, the server is 9 + * hours ahead. So, if I'm inputting say 12/24 at a couple of hours before midnight, at the + * server it is already 12/25. If this boolean is true, it will be transformed to 12/25, while + * the client sees 12/24. + * </p> + * + * @param datePattern + * The pattern to use. Must be not null. See {@link SimpleDateFormat} for available + * patterns. + * @param applyTimeZoneDifference + * whether to apply the difference in time zones between client and server + * @throws IllegalArgumentException + * in case the date pattern is null + */ + public PatternZonedDateTimeConverter(String datePattern, boolean applyTimeZoneDifference) + { + + super(applyTimeZoneDifference); + this.datePattern = Args.notNull(datePattern, "datePattern"); + } + + /** + * Gets the optional date pattern. + * + * @return datePattern + */ + @Override + public final String getPattern(Locale locale) + { + return datePattern; + } + + /** + * @return formatter The formatter for the current conversion + */ + @Override + public DateTimeFormatter getFormat(Locale locale) + { + return DateTimeFormatter.ofPattern(datePattern).withLocale(locale); + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleDateConverter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleDateConverter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleDateConverter.java index 14e6d22..79decad 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleDateConverter.java +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleDateConverter.java @@ -17,7 +17,6 @@ package org.apache.wicket.extensions.markup.html.form.datetime; import java.time.LocalDate; -import java.time.ZonedDateTime; import java.time.chrono.IsoChronology; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; @@ -25,7 +24,7 @@ import java.time.format.FormatStyle; import java.util.Locale; /** - * Date converter that uses Joda Time and can be configured to take the time zone difference between + * Date converter that uses javax.time and can be configured to take the time zone difference between * clients and server into account, and that is configured for a certain date style. The pattern * will always be locale specific. * <p> @@ -33,9 +32,8 @@ import java.util.Locale; * </p> * * @see org.apache.wicket.extensions.markup.html.form.DateTextField - * @see java.time.ZonedDateTime + * @see java.time.LocalDate * @see DateTimeFormatter - * @see java.time.ZoneId * * @author eelcohillenius */ @@ -60,33 +58,22 @@ public class StyleDateConverter extends LocalDateConverter /** * Construct. The provided pattern will be used as the base format (but they will be localized - * for the current locale) and if null, {@link DateTimeFormatter#ofLocalizedDate(FormatStyle)} will be used. </p> - * When applyTimeZoneDifference is true, the current time is applied on the parsed date, and the - * date will be corrected for the time zone difference between the server and the client. For - * instance, if I'm in Seattle and the server I'm working on is in Amsterdam, the server is 9 - * hours ahead. So, if I'm inputting say 12/24 at a couple of hours before midnight, at the - * server it is already 12/25. If this boolean is true, it will be transformed to 12/25, while - * the client sees 12/24. </p> + * for the current locale) and if null, {@link DateTimeFormatter#ofLocalizedDate(FormatStyle)} will be used. * * @param dateStyle * Date style to use. See {@link DateTimeFormatter#ofLocalizedDate(FormatStyle)}. - * @param timeStyle - * Time style to use. See {@link DateTimeFormatter#ofLocalizedTime(FormatStyle)} - * @param applyTimeZoneDifference - * whether to apply the difference in time zones between client and server * @throws IllegalArgumentException * in case dateStyle is null */ - public StyleDateConverter(FormatStyle dateStyle, FormatStyle timeStyle, boolean applyTimeZoneDifference) + public StyleDateConverter(FormatStyle dateStyle) { - super(applyTimeZoneDifference); + super(); this.dateStyle = dateStyle; - this.timeStyle = timeStyle; } - public StyleDateConverter(String dateTimeStyle, boolean applyTimeZoneDifference) + public StyleDateConverter(String dateStyle) { - this(parseFormatStyle(dateTimeStyle.charAt(0)), parseFormatStyle(dateTimeStyle.charAt(1)), applyTimeZoneDifference); + this(parseFormatStyle(dateStyle.charAt(0))); } /** @@ -97,8 +84,7 @@ public class StyleDateConverter extends LocalDateConverter @Override public final String getPattern(Locale locale) { - String localizedDateTimePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(dateStyle, timeStyle, IsoChronology.INSTANCE, locale); - return localizedDateTimePattern; + return DateTimeFormatterBuilder.getLocalizedDateTimePattern(dateStyle, null, IsoChronology.INSTANCE, locale); } /** @@ -107,23 +93,7 @@ public class StyleDateConverter extends LocalDateConverter @Override public DateTimeFormatter getFormat(Locale locale) { - DateTimeFormatter df = null; - if (dateStyle == null && timeStyle == null) { - return df; - } - if (timeStyle == null) - { - df = DateTimeFormatter.ofLocalizedDate(dateStyle); - } - else if (dateStyle == null) - { - df = DateTimeFormatter.ofLocalizedTime(timeStyle); - } - else - { - df = DateTimeFormatter.ofLocalizedDateTime(dateStyle, timeStyle); - } - return df.withLocale(locale); + return dateStyle == null ? null : DateTimeFormatter.ofLocalizedDate(dateStyle).withLocale(locale); } public static FormatStyle parseFormatStyle(char style) @@ -132,23 +102,13 @@ public class StyleDateConverter extends LocalDateConverter } @Override - public ZonedDateTime convertToObject(String value, DateTimeFormatter format, Locale locale) { + public LocalDate convertToObject(String value, DateTimeFormatter format, Locale locale) { if (format == null) { return null; } try { - if (timeStyle == null) - { - LocalDate d = LocalDate.parse(value, format); - return ZonedDateTime.of(d.atStartOfDay(), getTimeZone()); - } - else if (dateStyle == null) - { - // not sure how we can get ZonedDateTime from time - return null; - } - return super.convertToObject(value, format, locale); + return LocalDate.parse(value, format); } catch (RuntimeException e) { http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleTimeConverter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleTimeConverter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleTimeConverter.java new file mode 100644 index 0000000..8ac59b4 --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleTimeConverter.java @@ -0,0 +1,118 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.extensions.markup.html.form.datetime; + +import java.time.LocalTime; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.FormatStyle; +import java.util.Locale; + +/** + * Date converter that uses javax.time and can be configured to take the time zone difference between + * clients and server into account, and that is configured for a certain date style. The pattern + * will always be locale specific. + * <p> + * This converter is especially suited on a per-component base. + * </p> + * + * @see org.apache.wicket.extensions.markup.html.form.DateTextField + * @see java.time.LocalTime + * @see DateTimeFormatter + * + * @author eelcohillenius + */ +public class StyleTimeConverter extends LocalTimeConverter +{ + private static final long serialVersionUID = 1L; + + /** + * Date style to use. See {@link DateTimeFormatter#ofLocalizedDate(FormatStyle)}. + */ + private final FormatStyle timeStyle; + + /** + * Construct. The dateStyle 'S-' (which is the same as {@link DateTimeFormatter#ofLocalizedDate(FormatStyle)}) will + * be used for constructing the date format for the current locale. + * + */ + public StyleTimeConverter() + { + this(FormatStyle.SHORT); + } + + /** + * Construct. The provided pattern will be used as the base format (but they will be localized + * for the current locale) and if null, {@link DateTimeFormatter#ofLocalizedDate(FormatStyle)} will be used. + * + * @param timeStyle + * Date style to use. See {@link DateTimeFormatter#ofLocalizedDate(FormatStyle)}. + * @throws IllegalArgumentException + * in case dateStyle is null + */ + public StyleTimeConverter(FormatStyle timeStyle) + { + super(); + this.timeStyle = timeStyle; + } + + public StyleTimeConverter(String timeStyle) + { + this(parseFormatStyle(timeStyle.charAt(0))); + } + + /** + * Gets the optional time pattern. + * + * @return timePattern + */ + @Override + public final String getPattern(Locale locale) + { + return DateTimeFormatterBuilder.getLocalizedDateTimePattern(null, timeStyle, IsoChronology.INSTANCE, locale); + } + + /** + * @return formatter The formatter for the current conversion + */ + @Override + public DateTimeFormatter getFormat(Locale locale) + { + return timeStyle == null ? null : DateTimeFormatter.ofLocalizedDate(timeStyle).withLocale(locale); + } + + public static FormatStyle parseFormatStyle(char style) + { + return DateField.parseFormatStyle(style); + } + + @Override + public LocalTime convertToObject(String value, DateTimeFormatter format, Locale locale) { + if (format == null) { + return null; + } + try + { + return LocalTime.parse(value, format); + } + catch (RuntimeException e) + { + throw newConversionException(e, locale); + } + } +} http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleZonedDateTimeConverter.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleZonedDateTimeConverter.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleZonedDateTimeConverter.java index cb0f5be..c186cfe 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleZonedDateTimeConverter.java +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/StyleZonedDateTimeConverter.java @@ -25,7 +25,7 @@ import java.time.format.FormatStyle; import java.util.Locale; /** - * Date converter that uses Joda Time and can be configured to take the time zone difference between + * Date converter that uses javax.time and can be configured to take the time zone difference between * clients and server into account, and that is configured for a certain date style. The pattern * will always be locale specific. * <p> http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/TimeField.html ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/TimeField.html b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/TimeField.html new file mode 100644 index 0000000..82cb00d --- /dev/null +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/TimeField.html @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<wicket:panel xmlns:wicket="http://wicket.apache.org"> + <span style="white-space: nowrap;"> + <input type="number" wicket:id="hours" size="2" maxlength="2" /> + <span wicket:id="hoursSeparator"> :</span> + <input type="number" wicket:id="minutes" size="2" maxlength="2" /> + <select wicket:id="amOrPmChoice"></select> + </span> +</wicket:panel> http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/TimeField.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/TimeField.java b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/TimeField.java index aa0dea8..cf3cc29 100644 --- a/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/TimeField.java +++ b/wicket-extensions/src/main/java/org/apache/wicket/extensions/markup/html/form/datetime/TimeField.java @@ -16,10 +16,28 @@ */ package org.apache.wicket.extensions.markup.html.form.datetime; -import java.time.ZonedDateTime; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.time.LocalTime; +import java.time.chrono.IsoChronology; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.FormatStyle; +import java.time.temporal.ChronoField; +import java.util.Arrays; import java.util.Locale; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.markup.html.form.AbstractTextComponent.ITextFormatProvider; +import org.apache.wicket.markup.html.form.DropDownChoice; +import org.apache.wicket.markup.html.form.FormComponentPanel; +import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.util.convert.IConverter; +import org.apache.wicket.util.convert.converter.IntegerConverter; +import org.apache.wicket.util.lang.Args; +import org.apache.wicket.validation.validator.RangeValidator; /** * Works on a {@link java.util.Date} object. Displays a field for hours and a field for minutes, and @@ -28,21 +46,195 @@ import org.apache.wicket.model.IModel; * {@link TimeField#use12HourFormat}). * * @author eelcohillenius - * @see DateField for a variant with just the date field and date picker + * @see TimeField for a variant with just the date field and date picker */ -public class TimeField extends DateTimeField +public class TimeField extends FormComponentPanel<LocalTime> implements ITextFormatProvider { private static final long serialVersionUID = 1L; /** + * Enumerated type for different ways of handling the render part of requests. + */ + public enum AM_PM { + /** */ + AM("AM"), + + /** */ + PM("PM"); + + private final String value; + + AM_PM(final String name) + { + value = name; + } + + @Override + public String toString() + { + return value; + } + } + protected static final String HOURS = "hours"; + protected static final String MINUTES = "minutes"; + protected static final String AM_OR_PM_CHOICE = "amOrPmChoice"; + + private static final IConverter<Integer> MINUTES_CONVERTER = new IntegerConverter() { + private static final long serialVersionUID = 1L; + + protected NumberFormat newNumberFormat(Locale locale) { + return new DecimalFormat("00"); + } + }; + + // The TextField for "hours" and it's associated model object + private TextField<Integer> hoursField; + + // The TextField for "minutes" and it's associated model object + private TextField<Integer> minutesField; + + // The dropdown list for AM/PM and it's associated model object + private DropDownChoice<AM_PM> amOrPmChoice; + private LocalTime time = LocalTime.now(); + + /** + * Creates a new TimeField defaulting to using a short date pattern + * + * @param id + * The id of the text field + * @param model + * The model + * @param timePattern + * The pattern to use. Must be not null. See {@link SimpleDateFormat} for available + * patterns. + * @return TimeField + */ + public static TimeField forTimePattern(String id, IModel<LocalTime> model, String timePattern) + { + return new TimeField(id, model, new PatternTimeConverter(timePattern)); + } + + /** + * Creates a new TimeField defaulting to using a short date pattern + * + * @param id + * The id of the text field + * @param timePattern + * The pattern to use. Must be not null. See {@link SimpleDateFormat} for available + * patterns. + * @return TimeField + */ + public static TimeField forTimePattern(String id, String timePattern) + { + return forTimePattern(id, null, timePattern); + } + + /** + * Creates a new TimeField using the provided date style. + * + * @param id + * The id of the text field + * @param model + * The model + * @param timeStyle + * Date style to use. The first character is the date style, and the second character + * is the time style. Specify a character of 'S' for short style, 'M' for medium, 'L' + * for long, and 'F' for full. A date or time may be ommitted by specifying a style + * character '-'. See {@link org.joda.time.DateTimeFormat#forStyle(String)}. + * @return TimeField + */ + public static TimeField forTimeStyle(String id, IModel<LocalTime> model, String timeStyle) + { + return new TimeField(id, model, new StyleTimeConverter(timeStyle)); + } + + /** + * Creates a new TimeField using the provided date style. + * + * @param id + * The id of the text field + * @param timeStyle + * Date style to use. The first character is the date style, and the second character + * is the time style. Specify a character of 'S' for short style, 'M' for medium, 'L' + * for long, and 'F' for full. A date or time may be ommitted by specifying a style + * character '-'. See {@link org.joda.time.DateTimeFormat#forStyle(String)}. + * @return TimeField + */ + public static TimeField forTimeStyle(String id, String timeStyle) + { + return forTimeStyle(id, null, timeStyle); + } + + /** + * Creates a new TimeField defaulting to using a short date pattern + * + * @param id + * The id of the text field + * @return TimeField + */ + public static TimeField forShortStyle(String id) + { + return forShortStyle(id, null); + } + + /** + * Creates a new TimeField defaulting to using a short date pattern + * + * @param id + * The id of the text field + * @param model + * The model + * @return TimeField + */ + public static TimeField forShortStyle(String id, IModel<LocalTime> model) + { + return new TimeField(id, model, new StyleTimeConverter()); + } + + /** + * Creates a new TimeField using the provided converter. + * + * @param id + * The id of the text field + * @param converter + * the date converter + * @return TimeField + */ + public static TimeField withConverter(String id, IDateConverter<LocalTime> converter) + { + return withConverter(id, null, converter); + } + + /** + * Creates a new TimeField using the provided converter. + * + * @param id + * The id of the text field + * @param model + * The model + * @param converter + * the date converter + * @return TimeField + */ + public static TimeField withConverter(String id, IModel<LocalTime> model, IDateConverter<LocalTime> converter) + { + return new TimeField(id, model, converter); + } + + /** + * The converter for the TextField + */ + private final IDateConverter<LocalTime> converter; + + /** * Construct. * * @param id * the component id */ - public TimeField(String id) + public TimeField(String id, IDateConverter<LocalTime> converter) { - this(id, null); + this(id, null, converter); } /** @@ -53,19 +245,250 @@ public class TimeField extends DateTimeField * @param model * the component's model */ - public TimeField(String id, IModel<ZonedDateTime> model) + public TimeField(String id, IModel<LocalTime> model, IDateConverter<LocalTime> converter) { super(id, model); - getDateTextField().setVisibilityAllowed(false); + Args.notNull(converter, "converter"); + this.converter = converter; + + // Sets the type that will be used when updating the model for this component. + setType(LocalTime.class); + + + // Create and add the "hours" TextField + add(hoursField = newHoursTextField(HOURS, new HoursModel(), Integer.class)); + + // Create and add the "minutes" TextField + add(minutesField = newMinutesTextField(MINUTES, new MinutesModel(), Integer.class)); + + // Create and add the "AM/PM" Listbox + add(amOrPmChoice = new DropDownChoice<>(AM_OR_PM_CHOICE, new AmPmModel(), Arrays.asList(AM_PM.values()))); + + add(new WebMarkupContainer("hoursSeparator") + { + private static final long serialVersionUID = 1L; + + @Override + public boolean isVisible() + { + return minutesField.determineVisibility(); + } + }); + } + + /** + * create a new {@link TextField} instance for hours to be added to this panel. + * + * @param id + * the component id + * @param model + * model that should be used by the {@link TextField} + * @param type + * the type of the text field + * @return a new text field instance + */ + protected TextField<Integer> newHoursTextField(final String id, IModel<Integer> model, Class<Integer> type) { + TextField<Integer> hoursTextField = new TextField<>(id, model, type); + hoursTextField.add(getMaximumHours() == 24 ? RangeValidator.range(0, 23) : RangeValidator + .range(1, 12)); + hoursTextField.setLabel(new Model<>(HOURS)); + return hoursTextField; + } + + /** + * create a new {@link TextField} instance for minutes to be added to this panel. + * + * @param id + * the component id + * @param model + * model that should be used by the {@link TextField} + * @param type + * the type of the text field + * @return a new text field instance + */ + protected TextField<Integer> newMinutesTextField(final String id, IModel<Integer> model, + Class<Integer> type) + { + TextField<Integer> minutesField = new TextField<Integer>(id, model, type) + { + private static final long serialVersionUID = 1L; + + @Override + protected IConverter<?> createConverter(Class<?> type) + { + if (Integer.class.isAssignableFrom(type)) + { + return MINUTES_CONVERTER; + } + return null; + } + }; + minutesField.add(new RangeValidator<>(0, 59)); + minutesField.setLabel(new Model<>(MINUTES)); + return minutesField; + } + + @Override + public String getInput() + { + // since we override convertInput, we can let this method return a value + // that is just suitable for error reporting + return String.format("%s:%s", hoursField.getInput(), minutesField.getInput()); } @Override public void convertInput() { - ZonedDateTime modelObject = getModelObject(); - getDateTextField().setConvertedInput(modelObject != null ? modelObject.toLocalDate() : newDateInstance()); + Integer hoursInput = hoursField.getConvertedInput(); + Integer minutesInput = minutesField.getConvertedInput(); + AM_PM amOrPmInput = amOrPmChoice.getConvertedInput(); + + // Use the input to create a date object with proper timezone + LocalTime localTime = LocalTime.of(hoursInput, minutesInput); + + // Adjust for halfday if needed + if (use12HourFormat()) + { + int halfday = (amOrPmInput == AM_PM.PM ? 1 : 0); + localTime = localTime.with(ChronoField.AMPM_OF_DAY, halfday); + } super.convertInput(); } + @Override + protected void onBeforeRender() { + hoursField.setRequired(isRequired()); + minutesField.setRequired(isRequired()); + + boolean use12HourFormat = use12HourFormat(); + amOrPmChoice.setVisible(use12HourFormat); + super.onBeforeRender(); + } + + /** + * Checks whether the current {@link Locale} uses the 12h or 24h time format. This method can be + * overridden to e.g. always use 24h format. + * + * @return true, if the current {@link Locale} uses the 12h format.<br/> + * false, otherwise + */ + protected boolean use12HourFormat() + { + String pattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern(null, FormatStyle.SHORT, IsoChronology.INSTANCE, getLocale()); + return pattern.indexOf('a') != -1 || pattern.indexOf('h') != -1 || pattern.indexOf('K') != -1; + } + + /** + * @return either 12 or 24, depending on the hour format of the current {@link Locale} + */ + private int getMaximumHours() + { + return getMaximumHours(use12HourFormat()); + } + + /** + * Convenience method (mainly for optimization purposes), in case {@link #use12HourFormat()} has + * already been stored in a local variable and thus doesn't need to be computed again. + * + * @param use12HourFormat + * the hour format to use + * @return either 12 or 24, depending on the parameter <code>use12HourFormat</code> + */ + private int getMaximumHours(boolean use12HourFormat) + { + return use12HourFormat ? 12 : 24; + } + + + protected class HoursModel implements IModel<Integer> + { + private static final long serialVersionUID = 1L; + + @Override + public Integer getObject() + { + return time.getHour(); + } + + @Override + public void setObject(Integer hour) + { + time = time.with(ChronoField.HOUR_OF_DAY, hour); + } + + @Override + public void detach() + { + } + } + + protected class MinutesModel implements IModel<Integer> + { + private static final long serialVersionUID = 1L; + + @Override + public Integer getObject() + { + return time.getMinute(); + } + + @Override + public void setObject(Integer minute) + { + time = time.with(ChronoField.MINUTE_OF_HOUR, minute); + } + + @Override + public void detach() + { + } + } + + protected class AmPmModel implements IModel<AM_PM> + { + private static final long serialVersionUID = 1L; + + @Override + public AM_PM getObject() + { + int i = time.get(ChronoField.AMPM_OF_DAY); + return i == 0 ? AM_PM.AM : AM_PM.PM; + } + + @Override + public void setObject(AM_PM amPm) + { + int i = AM_PM.AM == amPm ? 0 : 1; + time = time.with(ChronoField.AMPM_OF_DAY, i); + } + + @Override + public void detach() + { + } + } + + /** + * @return The specialized converter. + * @see org.apache.wicket.Component#createConverter(java.lang.Class) + */ + @Override + protected IConverter<?> createConverter(Class<?> clazz) + { + if (LocalTime.class.isAssignableFrom(clazz)) + { + return converter; + } + return null; + } + + /** + * @see org.apache.wicket.markup.html.form.AbstractTextComponent.ITextFormatProvider#getTextFormat() + */ + @Override + public final String getTextFormat() + { + return converter.getPattern(getLocale()); + } } http://git-wip-us.apache.org/repos/asf/wicket/blob/2f1b9251/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/form/datetime/DateConverterTest.java ---------------------------------------------------------------------- diff --git a/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/form/datetime/DateConverterTest.java b/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/form/datetime/DateConverterTest.java index 73c5035..d590615 100644 --- a/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/form/datetime/DateConverterTest.java +++ b/wicket-extensions/src/test/java/org/apache/wicket/extensions/markup/html/form/datetime/DateConverterTest.java @@ -23,7 +23,7 @@ import java.util.Calendar; import java.util.Date; import java.util.Locale; -import org.apache.wicket.extensions.markup.html.form.datetime.PatternDateConverter; +import org.apache.wicket.extensions.markup.html.form.datetime.PatternZonedDateTimeConverter; import org.apache.wicket.extensions.markup.html.form.datetime.StyleZonedDateTimeConverter; import org.apache.wicket.util.convert.ConversionException; import org.apache.wicket.util.convert.IConverter; @@ -51,7 +51,7 @@ public class DateConverterTest Assert.assertEquals(locale, styleFormatter.getLocale()); - PatternDateConverter patternDateConverter = new PatternDateConverter( + PatternZonedDateTimeConverter patternDateConverter = new PatternZonedDateTimeConverter( styleDateConverter.getPattern(locale), false); DateTimeFormatter patternFormatter = patternDateConverter.getFormat(locale);
