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.

VDateTimeCalendarPanel.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /*
  2. * Copyright 2000-2018 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.client.ui;
  17. import java.util.Date;
  18. import com.google.gwt.event.dom.client.ChangeEvent;
  19. import com.google.gwt.event.dom.client.ChangeHandler;
  20. import com.google.gwt.event.dom.client.KeyCodes;
  21. import com.google.gwt.user.client.Element;
  22. import com.google.gwt.user.client.ui.FlowPanel;
  23. import com.google.gwt.user.client.ui.ListBox;
  24. import com.google.gwt.user.client.ui.Widget;
  25. import com.vaadin.client.DateTimeService;
  26. import com.vaadin.shared.ui.datefield.DateTimeResolution;
  27. /**
  28. * @author Vaadin Ltd
  29. * @since 8.0
  30. */
  31. public class VDateTimeCalendarPanel
  32. extends VAbstractCalendarPanel<DateTimeResolution> {
  33. private static final String SUBPART_HOUR_SELECT = "h";
  34. private static final String SUBPART_MINUTE_SELECT = "m";
  35. private static final String SUBPART_SECS_SELECT = "s";
  36. private static final String SUBPART_AMPM_SELECT = "ampm";
  37. private TimeChangeListener timeChangeListener;
  38. private VTime time;
  39. /**
  40. * TimeSelector is a widget consisting of list boxes that modify the Date
  41. * object that is given for.
  42. *
  43. */
  44. public class VTime extends FlowPanel implements ChangeHandler {
  45. private ListBox hours;
  46. private ListBox mins;
  47. private ListBox sec;
  48. private ListBox ampm;
  49. /**
  50. * Constructor.
  51. */
  52. public VTime() {
  53. super();
  54. setStyleName(VDateField.CLASSNAME + "-time");
  55. buildTime();
  56. }
  57. private ListBox createListBox() {
  58. ListBox lb = new ListBox();
  59. lb.setStyleName("v-select");
  60. lb.addChangeHandler(this);
  61. lb.addBlurHandler(VDateTimeCalendarPanel.this);
  62. lb.addFocusHandler(VDateTimeCalendarPanel.this);
  63. return lb;
  64. }
  65. /**
  66. * Constructs the ListBoxes and updates their value
  67. *
  68. */
  69. private void buildTime() {
  70. clear();
  71. hours = createListBox();
  72. if (getDateTimeService().isTwelveHourClock()) {
  73. hours.addItem("12");
  74. for (int i = 1; i < 12; i++) {
  75. hours.addItem(DateTimeService.asTwoDigits(i));
  76. }
  77. } else {
  78. for (int i = 0; i < 24; i++) {
  79. hours.addItem(DateTimeService.asTwoDigits(i));
  80. }
  81. }
  82. hours.addChangeHandler(this);
  83. if (getDateTimeService().isTwelveHourClock()) {
  84. ampm = createListBox();
  85. final String[] ampmText = getDateTimeService().getAmPmStrings();
  86. ampm.addItem(ampmText[0]);
  87. ampm.addItem(ampmText[1]);
  88. ampm.addChangeHandler(this);
  89. }
  90. if (getResolution().compareTo(DateTimeResolution.MINUTE) <= 0) {
  91. mins = createListBox();
  92. for (int i = 0; i < 60; i++) {
  93. mins.addItem(DateTimeService.asTwoDigits(i));
  94. }
  95. mins.addChangeHandler(this);
  96. }
  97. if (getResolution().compareTo(DateTimeResolution.SECOND) <= 0) {
  98. sec = createListBox();
  99. for (int i = 0; i < 60; i++) {
  100. sec.addItem(DateTimeService.asTwoDigits(i));
  101. }
  102. sec.addChangeHandler(this);
  103. }
  104. // Update times
  105. updateTimes();
  106. final String delimiter = getDateTimeService().getClockDelimeter();
  107. if (isReadonly()) {
  108. int h = 0;
  109. if (getDate() != null) {
  110. h = getDate().getHours();
  111. }
  112. if (getDateTimeService().isTwelveHourClock()) {
  113. h -= h < 12 ? 0 : 12;
  114. }
  115. add(new VLabel(DateTimeService.asTwoDigits(h)));
  116. } else {
  117. add(hours);
  118. }
  119. if (getResolution().compareTo(DateTimeResolution.MINUTE) <= 0) {
  120. add(new VLabel(delimiter));
  121. if (isReadonly()) {
  122. final int m = mins.getSelectedIndex();
  123. add(new VLabel(DateTimeService.asTwoDigits(m)));
  124. } else {
  125. add(mins);
  126. }
  127. }
  128. if (getResolution().compareTo(DateTimeResolution.SECOND) <= 0) {
  129. add(new VLabel(delimiter));
  130. if (isReadonly()) {
  131. final int s = sec.getSelectedIndex();
  132. add(new VLabel(DateTimeService.asTwoDigits(s)));
  133. } else {
  134. add(sec);
  135. }
  136. }
  137. if (getResolution() == DateTimeResolution.HOUR) {
  138. add(new VLabel(delimiter + "00")); // o'clock
  139. }
  140. if (getDateTimeService().isTwelveHourClock()) {
  141. add(new VLabel("&nbsp;"));
  142. if (isReadonly()) {
  143. int i = 0;
  144. if (getDate() != null) {
  145. i = (getDate().getHours() < 12) ? 0 : 1;
  146. }
  147. add(new VLabel(ampm.getItemText(i)));
  148. } else {
  149. add(ampm);
  150. }
  151. }
  152. if (isReadonly()) {
  153. return;
  154. }
  155. ListBox lastDropDown = getLastDropDown();
  156. lastDropDown.addKeyDownHandler(event -> {
  157. boolean shiftKey = event.getNativeEvent().getShiftKey();
  158. if (!shiftKey) {
  159. int nativeKeyCode = event.getNativeKeyCode();
  160. if (nativeKeyCode == KeyCodes.KEY_TAB) {
  161. onTabOut(event);
  162. }
  163. }
  164. });
  165. }
  166. private ListBox getLastDropDown() {
  167. int i = getWidgetCount() - 1;
  168. while (i >= 0) {
  169. Widget widget = getWidget(i);
  170. if (widget instanceof ListBox) {
  171. return (ListBox) widget;
  172. }
  173. i--;
  174. }
  175. return null;
  176. }
  177. /**
  178. * Updates the value to correspond to the values in value.
  179. */
  180. public void updateTimes() {
  181. if (getDate() == null) {
  182. setDate(new Date());
  183. }
  184. if (getDateTimeService().isTwelveHourClock()) {
  185. int h = getDate().getHours();
  186. ampm.setSelectedIndex(h < 12 ? 0 : 1);
  187. h -= ampm.getSelectedIndex() * 12;
  188. hours.setSelectedIndex(h);
  189. } else {
  190. hours.setSelectedIndex(getDate().getHours());
  191. }
  192. if (getResolution().compareTo(DateTimeResolution.MINUTE) <= 0) {
  193. mins.setSelectedIndex(getDate().getMinutes());
  194. }
  195. if (getResolution().compareTo(DateTimeResolution.SECOND) <= 0) {
  196. sec.setSelectedIndex(getDate().getSeconds());
  197. }
  198. if (getDateTimeService().isTwelveHourClock()) {
  199. ampm.setSelectedIndex(getDate().getHours() < 12 ? 0 : 1);
  200. }
  201. hours.setEnabled(isEnabled());
  202. if (mins != null) {
  203. mins.setEnabled(isEnabled());
  204. }
  205. if (sec != null) {
  206. sec.setEnabled(isEnabled());
  207. }
  208. if (ampm != null) {
  209. ampm.setEnabled(isEnabled());
  210. }
  211. }
  212. private DateTimeService getDateTimeService() {
  213. DateTimeService dts = VDateTimeCalendarPanel.this
  214. .getDateTimeService();
  215. if (dts == null) {
  216. dts = new DateTimeService();
  217. setDateTimeService(dts);
  218. }
  219. return dts;
  220. }
  221. /*
  222. * (non-Javadoc) VT
  223. *
  224. * @see
  225. * com.google.gwt.event.dom.client.ChangeHandler#onChange(com.google.gwt
  226. * .event.dom.client.ChangeEvent)
  227. */
  228. @Override
  229. public void onChange(ChangeEvent event) {
  230. /*
  231. * Value from dropdowns gets always set for the value. Like year and
  232. * month when resolution is month or year.
  233. */
  234. if (event.getSource() == hours) {
  235. int h = hours.getSelectedIndex();
  236. if (getDateTimeService().isTwelveHourClock()) {
  237. h = h + ampm.getSelectedIndex() * 12;
  238. }
  239. getDate().setHours(h);
  240. if (timeChangeListener != null) {
  241. timeChangeListener.changed(h, getDate().getMinutes(),
  242. getDate().getSeconds(),
  243. DateTimeService.getMilliseconds(getDate()));
  244. }
  245. event.preventDefault();
  246. event.stopPropagation();
  247. } else if (event.getSource() == mins) {
  248. final int m = mins.getSelectedIndex();
  249. getDate().setMinutes(m);
  250. if (timeChangeListener != null) {
  251. timeChangeListener.changed(getDate().getHours(), m,
  252. getDate().getSeconds(),
  253. DateTimeService.getMilliseconds(getDate()));
  254. }
  255. event.preventDefault();
  256. event.stopPropagation();
  257. } else if (event.getSource() == sec) {
  258. final int s = sec.getSelectedIndex();
  259. getDate().setSeconds(s);
  260. if (timeChangeListener != null) {
  261. timeChangeListener.changed(getDate().getHours(),
  262. getDate().getMinutes(), s,
  263. DateTimeService.getMilliseconds(getDate()));
  264. }
  265. event.preventDefault();
  266. event.stopPropagation();
  267. } else if (event.getSource() == ampm) {
  268. final int h = hours.getSelectedIndex()
  269. + (ampm.getSelectedIndex() * 12);
  270. getDate().setHours(h);
  271. if (timeChangeListener != null) {
  272. timeChangeListener.changed(h, getDate().getMinutes(),
  273. getDate().getSeconds(),
  274. DateTimeService.getMilliseconds(getDate()));
  275. }
  276. event.preventDefault();
  277. event.stopPropagation();
  278. }
  279. }
  280. }
  281. /**
  282. * Dispatches an event when the panel when time is changed.
  283. */
  284. public interface TimeChangeListener {
  285. void changed(int hour, int min, int sec, int msec);
  286. }
  287. /**
  288. * The time change listener is triggered when the user changes the time.
  289. *
  290. * @param listener
  291. */
  292. public void setTimeChangeListener(TimeChangeListener listener) {
  293. timeChangeListener = listener;
  294. }
  295. @Override
  296. public void setDate(Date currentDate) {
  297. doSetDate(currentDate, isTimeSelectorNeeded() && time == null, () -> {
  298. if (isTimeSelectorNeeded()) {
  299. time.updateTimes();
  300. }
  301. });
  302. }
  303. @Override
  304. public void setResolution(DateTimeResolution resolution) {
  305. super.setResolution(resolution);
  306. if (isTimeSelectorNeeded() && time != null) {
  307. // resolution has changed => rebuild time UI
  308. time.buildTime();
  309. }
  310. }
  311. @Override
  312. protected boolean acceptDayFocus() {
  313. return getResolution().compareTo(DateTimeResolution.MONTH) < 0;
  314. }
  315. @Override
  316. protected boolean isDay(DateTimeResolution resolution) {
  317. return DateTimeResolution.DAY.equals(resolution);
  318. }
  319. @Override
  320. protected boolean isMonth(DateTimeResolution resolution) {
  321. return DateTimeResolution.MONTH.equals(resolution);
  322. }
  323. @Override
  324. protected boolean isBelowMonth(DateTimeResolution resolution) {
  325. return resolution.compareTo(DateTimeResolution.MONTH) < 0;
  326. }
  327. @Override
  328. protected void doRenderCalendar(boolean updateDate) {
  329. super.doRenderCalendar(updateDate);
  330. if (isTimeSelectorNeeded()) {
  331. time = new VTime();
  332. setWidget(2, 0, time);
  333. getFlexCellFormatter().setColSpan(2, 0, 5);
  334. getFlexCellFormatter().setStyleName(2, 0,
  335. getDateField().getStylePrimaryName()
  336. + "-calendarpanel-time");
  337. } else if (time != null) {
  338. remove(time);
  339. }
  340. }
  341. @Override
  342. public String getSubPartName(Element subElement) {
  343. if (time != null) {
  344. if (contains(time.hours, subElement)) {
  345. return SUBPART_HOUR_SELECT;
  346. } else if (contains(time.mins, subElement)) {
  347. return SUBPART_MINUTE_SELECT;
  348. } else if (contains(time.sec, subElement)) {
  349. return SUBPART_SECS_SELECT;
  350. } else if (contains(time.ampm, subElement)) {
  351. return SUBPART_AMPM_SELECT;
  352. }
  353. }
  354. return super.getSubPartName(subElement);
  355. }
  356. @Override
  357. public Element getSubPartElement(String subPart) {
  358. if (SUBPART_HOUR_SELECT.equals(subPart)) {
  359. return time.hours.getElement();
  360. }
  361. if (SUBPART_MINUTE_SELECT.equals(subPart)) {
  362. return time.mins.getElement();
  363. }
  364. if (SUBPART_SECS_SELECT.equals(subPart)) {
  365. return time.sec.getElement();
  366. }
  367. if (SUBPART_AMPM_SELECT.equals(subPart)) {
  368. return time.ampm.getElement();
  369. }
  370. return super.getSubPartElement(subPart);
  371. }
  372. /**
  373. * Do we need the time selector
  374. *
  375. * @return True if it is required
  376. */
  377. private boolean isTimeSelectorNeeded() {
  378. return getResolution().compareTo(DateTimeResolution.DAY) < 0;
  379. }
  380. }