You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VTextualDate.java 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.client.ui;
  5. import java.util.Date;
  6. import com.google.gwt.event.dom.client.BlurEvent;
  7. import com.google.gwt.event.dom.client.BlurHandler;
  8. import com.google.gwt.event.dom.client.ChangeEvent;
  9. import com.google.gwt.event.dom.client.ChangeHandler;
  10. import com.google.gwt.event.dom.client.FocusEvent;
  11. import com.google.gwt.event.dom.client.FocusHandler;
  12. import com.google.gwt.user.client.Element;
  13. import com.google.gwt.user.client.ui.TextBox;
  14. import com.vaadin.terminal.gwt.client.EventId;
  15. import com.vaadin.terminal.gwt.client.Focusable;
  16. import com.vaadin.terminal.gwt.client.LocaleNotLoadedException;
  17. import com.vaadin.terminal.gwt.client.LocaleService;
  18. import com.vaadin.terminal.gwt.client.VConsole;
  19. public class VTextualDate extends VDateField implements Field, ChangeHandler,
  20. Focusable, SubPartAware {
  21. private static final String PARSE_ERROR_CLASSNAME = CLASSNAME
  22. + "-parseerror";
  23. protected final TextBox text;
  24. protected String formatStr;
  25. protected boolean lenient;
  26. private static final String CLASSNAME_PROMPT = "prompt";
  27. protected static final String ATTR_INPUTPROMPT = "prompt";
  28. protected String inputPrompt = "";
  29. private boolean prompting = false;
  30. public VTextualDate() {
  31. super();
  32. text = new TextBox();
  33. // use normal textfield styles as a basis
  34. text.setStyleName(VTextField.CLASSNAME);
  35. // add datefield spesific style name also
  36. text.addStyleName(CLASSNAME + "-textfield");
  37. text.addChangeHandler(this);
  38. text.addFocusHandler(new FocusHandler() {
  39. public void onFocus(FocusEvent event) {
  40. text.addStyleName(VTextField.CLASSNAME + "-"
  41. + VTextField.CLASSNAME_FOCUS);
  42. if (prompting) {
  43. text.setText("");
  44. setPrompting(false);
  45. }
  46. if (getClient() != null
  47. && getClient().hasEventListeners(VTextualDate.this,
  48. EventId.FOCUS)) {
  49. getClient()
  50. .updateVariable(getId(), EventId.FOCUS, "", true);
  51. }
  52. }
  53. });
  54. text.addBlurHandler(new BlurHandler() {
  55. public void onBlur(BlurEvent event) {
  56. text.removeStyleName(VTextField.CLASSNAME + "-"
  57. + VTextField.CLASSNAME_FOCUS);
  58. String value = getText();
  59. setPrompting(inputPrompt != null
  60. && (value == null || "".equals(value)));
  61. if (prompting) {
  62. text.setText(readonly ? "" : inputPrompt);
  63. }
  64. if (getClient() != null
  65. && getClient().hasEventListeners(VTextualDate.this,
  66. EventId.BLUR)) {
  67. getClient().updateVariable(getId(), EventId.BLUR, "", true);
  68. }
  69. }
  70. });
  71. add(text);
  72. }
  73. protected String getFormatString() {
  74. if (formatStr == null) {
  75. if (currentResolution == RESOLUTION_YEAR) {
  76. formatStr = "yyyy"; // force full year
  77. } else {
  78. try {
  79. String frmString = LocaleService
  80. .getDateFormat(currentLocale);
  81. frmString = cleanFormat(frmString);
  82. // String delim = LocaleService
  83. // .getClockDelimiter(currentLocale);
  84. if (currentResolution >= RESOLUTION_HOUR) {
  85. if (dts.isTwelveHourClock()) {
  86. frmString += " hh";
  87. } else {
  88. frmString += " HH";
  89. }
  90. if (currentResolution >= RESOLUTION_MIN) {
  91. frmString += ":mm";
  92. if (currentResolution >= RESOLUTION_SEC) {
  93. frmString += ":ss";
  94. }
  95. }
  96. if (dts.isTwelveHourClock()) {
  97. frmString += " aaa";
  98. }
  99. }
  100. formatStr = frmString;
  101. } catch (LocaleNotLoadedException e) {
  102. // TODO should die instead? Can the component survive
  103. // without format string?
  104. VConsole.error(e);
  105. }
  106. }
  107. }
  108. return formatStr;
  109. }
  110. /**
  111. * Updates the text field according to the current date (provided by
  112. * {@link #getDate()}). Takes care of updating text, enabling and disabling
  113. * the field, setting/removing readonly status and updating readonly styles.
  114. *
  115. * TODO: Split part of this into a method that only updates the text as this
  116. * is what usually is needed except for updateFromUIDL.
  117. */
  118. protected void buildDate() {
  119. removeStyleName(PARSE_ERROR_CLASSNAME);
  120. // Create the initial text for the textfield
  121. String dateText;
  122. Date currentDate = getDate();
  123. if (currentDate != null) {
  124. dateText = getDateTimeService().formatDate(currentDate,
  125. getFormatString());
  126. } else {
  127. dateText = "";
  128. }
  129. setText(dateText);
  130. text.setEnabled(enabled);
  131. text.setReadOnly(readonly);
  132. if (readonly) {
  133. text.addStyleName("v-readonly");
  134. } else {
  135. text.removeStyleName("v-readonly");
  136. }
  137. }
  138. protected void setPrompting(boolean prompting) {
  139. this.prompting = prompting;
  140. if (prompting) {
  141. addStyleDependentName(CLASSNAME_PROMPT);
  142. } else {
  143. removeStyleDependentName(CLASSNAME_PROMPT);
  144. }
  145. }
  146. @SuppressWarnings("deprecation")
  147. public void onChange(ChangeEvent event) {
  148. if (!text.getText().equals("")) {
  149. try {
  150. String enteredDate = text.getText();
  151. setDate(getDateTimeService().parseDate(enteredDate,
  152. getFormatString(), lenient));
  153. if (lenient) {
  154. // If date value was leniently parsed, normalize text
  155. // presentation.
  156. // FIXME: Add a description/example here of when this is
  157. // needed
  158. text.setValue(
  159. getDateTimeService().formatDate(getDate(),
  160. getFormatString()), false);
  161. }
  162. // remove possibly added invalid value indication
  163. removeStyleName(PARSE_ERROR_CLASSNAME);
  164. } catch (final Exception e) {
  165. VConsole.log(e);
  166. addStyleName(PARSE_ERROR_CLASSNAME);
  167. // this is a hack that may eventually be removed
  168. getClient().updateVariable(getId(), "lastInvalidDateString",
  169. text.getText(), false);
  170. setDate(null);
  171. }
  172. } else {
  173. setDate(null);
  174. // remove possibly added invalid value indication
  175. removeStyleName(PARSE_ERROR_CLASSNAME);
  176. }
  177. // always send the date string
  178. getClient()
  179. .updateVariable(getId(), "dateString", text.getText(), false);
  180. // Update variables
  181. // (only the smallest defining resolution needs to be
  182. // immediate)
  183. Date currentDate = getDate();
  184. getClient().updateVariable(getId(), "year",
  185. currentDate != null ? currentDate.getYear() + 1900 : -1,
  186. currentResolution == VDateField.RESOLUTION_YEAR && immediate);
  187. if (currentResolution >= VDateField.RESOLUTION_MONTH) {
  188. getClient().updateVariable(
  189. getId(),
  190. "month",
  191. currentDate != null ? currentDate.getMonth() + 1 : -1,
  192. currentResolution == VDateField.RESOLUTION_MONTH
  193. && immediate);
  194. }
  195. if (currentResolution >= VDateField.RESOLUTION_DAY) {
  196. getClient()
  197. .updateVariable(
  198. getId(),
  199. "day",
  200. currentDate != null ? currentDate.getDate() : -1,
  201. currentResolution == VDateField.RESOLUTION_DAY
  202. && immediate);
  203. }
  204. if (currentResolution >= VDateField.RESOLUTION_HOUR) {
  205. getClient().updateVariable(
  206. getId(),
  207. "hour",
  208. currentDate != null ? currentDate.getHours() : -1,
  209. currentResolution == VDateField.RESOLUTION_HOUR
  210. && immediate);
  211. }
  212. if (currentResolution >= VDateField.RESOLUTION_MIN) {
  213. getClient()
  214. .updateVariable(
  215. getId(),
  216. "min",
  217. currentDate != null ? currentDate.getMinutes() : -1,
  218. currentResolution == VDateField.RESOLUTION_MIN
  219. && immediate);
  220. }
  221. if (currentResolution >= VDateField.RESOLUTION_SEC) {
  222. getClient()
  223. .updateVariable(
  224. getId(),
  225. "sec",
  226. currentDate != null ? currentDate.getSeconds() : -1,
  227. currentResolution == VDateField.RESOLUTION_SEC
  228. && immediate);
  229. }
  230. }
  231. private String cleanFormat(String format) {
  232. // Remove unnecessary d & M if resolution is too low
  233. if (currentResolution < VDateField.RESOLUTION_DAY) {
  234. format = format.replaceAll("d", "");
  235. }
  236. if (currentResolution < VDateField.RESOLUTION_MONTH) {
  237. format = format.replaceAll("M", "");
  238. }
  239. // Remove unsupported patterns
  240. // TODO support for 'G', era designator (used at least in Japan)
  241. format = format.replaceAll("[GzZwWkK]", "");
  242. // Remove extra delimiters ('/' and '.')
  243. while (format.startsWith("/") || format.startsWith(".")
  244. || format.startsWith("-")) {
  245. format = format.substring(1);
  246. }
  247. while (format.endsWith("/") || format.endsWith(".")
  248. || format.endsWith("-")) {
  249. format = format.substring(0, format.length() - 1);
  250. }
  251. // Remove duplicate delimiters
  252. format = format.replaceAll("//", "/");
  253. format = format.replaceAll("\\.\\.", ".");
  254. format = format.replaceAll("--", "-");
  255. return format.trim();
  256. }
  257. public void focus() {
  258. text.setFocus(true);
  259. }
  260. protected String getText() {
  261. if (prompting) {
  262. return "";
  263. }
  264. return text.getText();
  265. }
  266. protected void setText(String text) {
  267. if (inputPrompt != null && (text == null || "".equals(text))) {
  268. text = readonly ? "" : inputPrompt;
  269. setPrompting(true);
  270. } else {
  271. setPrompting(false);
  272. }
  273. this.text.setText(text);
  274. }
  275. private final String TEXTFIELD_ID = "field";
  276. public Element getSubPartElement(String subPart) {
  277. if (subPart.equals(TEXTFIELD_ID)) {
  278. return text.getElement();
  279. }
  280. return null;
  281. }
  282. public String getSubPartName(Element subElement) {
  283. if (text.getElement().isOrHasChild(subElement)) {
  284. return TEXTFIELD_ID;
  285. }
  286. return null;
  287. }
  288. }