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

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