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.

DateCell.java 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. /*
  2. * Copyright 2000-2014 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.calendar.schedule;
  17. import java.util.ArrayList;
  18. import java.util.Date;
  19. import java.util.HashMap;
  20. import java.util.LinkedList;
  21. import java.util.List;
  22. import java.util.Map;
  23. import com.google.gwt.dom.client.Element;
  24. import com.google.gwt.dom.client.NativeEvent;
  25. import com.google.gwt.dom.client.Node;
  26. import com.google.gwt.dom.client.NodeList;
  27. import com.google.gwt.dom.client.Style.Display;
  28. import com.google.gwt.dom.client.Style.Unit;
  29. import com.google.gwt.event.dom.client.ContextMenuEvent;
  30. import com.google.gwt.event.dom.client.ContextMenuHandler;
  31. import com.google.gwt.event.dom.client.KeyCodes;
  32. import com.google.gwt.event.dom.client.KeyDownEvent;
  33. import com.google.gwt.event.dom.client.KeyDownHandler;
  34. import com.google.gwt.event.dom.client.MouseDownEvent;
  35. import com.google.gwt.event.dom.client.MouseDownHandler;
  36. import com.google.gwt.event.dom.client.MouseMoveEvent;
  37. import com.google.gwt.event.dom.client.MouseMoveHandler;
  38. import com.google.gwt.event.dom.client.MouseUpEvent;
  39. import com.google.gwt.event.dom.client.MouseUpHandler;
  40. import com.google.gwt.event.shared.HandlerRegistration;
  41. import com.google.gwt.user.client.DOM;
  42. import com.google.gwt.user.client.Event;
  43. import com.google.gwt.user.client.ui.Widget;
  44. import com.vaadin.client.WidgetUtil;
  45. public class DateCell extends FocusableComplexPanel implements
  46. MouseDownHandler, MouseMoveHandler, MouseUpHandler, KeyDownHandler,
  47. ContextMenuHandler {
  48. private static final String DRAGEMPHASISSTYLE = " dragemphasis";
  49. private Date date;
  50. private int width;
  51. private int eventRangeStart = -1;
  52. private int eventRangeStop = -1;
  53. final WeekGrid weekgrid;
  54. private boolean disabled = false;
  55. private int height;
  56. private final Element[] slotElements;
  57. private final List<DateCellSlot> slots = new ArrayList<DateCell.DateCellSlot>();
  58. private int[] slotElementHeights;
  59. private int startingSlotHeight;
  60. private Date today;
  61. private Element todaybar;
  62. private final List<HandlerRegistration> handlers;
  63. private final int numberOfSlots;
  64. private final int firstHour;
  65. private final int lastHour;
  66. public class DateCellSlot extends Widget {
  67. private final DateCell cell;
  68. private final Date from;
  69. private final Date to;
  70. public DateCellSlot(DateCell cell, Date from, Date to) {
  71. setElement(DOM.createDiv());
  72. getElement().setInnerHTML("&nbsp;");
  73. this.cell = cell;
  74. this.from = from;
  75. this.to = to;
  76. }
  77. public Date getFrom() {
  78. return from;
  79. }
  80. public Date getTo() {
  81. return to;
  82. }
  83. public DateCell getParentCell() {
  84. return cell;
  85. }
  86. }
  87. public DateCell(WeekGrid parent, Date date) {
  88. weekgrid = parent;
  89. Element mainElement = DOM.createDiv();
  90. setElement(mainElement);
  91. makeFocusable();
  92. setDate(date);
  93. addStyleName("v-calendar-day-times");
  94. handlers = new LinkedList<HandlerRegistration>();
  95. // 2 slots / hour
  96. firstHour = weekgrid.getFirstHour();
  97. lastHour = weekgrid.getLastHour();
  98. numberOfSlots = (lastHour - firstHour + 1) * 2;
  99. long slotTime = Math.round(((lastHour - firstHour + 1) * 3600000.0)
  100. / numberOfSlots);
  101. slotElements = new Element[numberOfSlots];
  102. slotElementHeights = new int[numberOfSlots];
  103. slots.clear();
  104. long start = getDate().getTime() + firstHour * 3600000;
  105. long end = start + slotTime;
  106. for (int i = 0; i < numberOfSlots; i++) {
  107. DateCellSlot slot = new DateCellSlot(this, new Date(start),
  108. new Date(end));
  109. if (i % 2 == 0) {
  110. slot.setStyleName("v-datecellslot-even");
  111. } else {
  112. slot.setStyleName("v-datecellslot");
  113. }
  114. Event.sinkEvents(slot.getElement(), Event.MOUSEEVENTS);
  115. mainElement.appendChild(slot.getElement());
  116. slotElements[i] = slot.getElement();
  117. slots.add(slot);
  118. start = end;
  119. end = start + slotTime;
  120. }
  121. // Sink events for tooltip handling
  122. Event.sinkEvents(mainElement, Event.MOUSEEVENTS);
  123. }
  124. public int getFirstHour() {
  125. return firstHour;
  126. }
  127. public int getLastHour() {
  128. return lastHour;
  129. }
  130. @Override
  131. protected void onAttach() {
  132. super.onAttach();
  133. handlers.add(addHandler(this, MouseDownEvent.getType()));
  134. handlers.add(addHandler(this, MouseUpEvent.getType()));
  135. handlers.add(addHandler(this, MouseMoveEvent.getType()));
  136. handlers.add(addDomHandler(this, ContextMenuEvent.getType()));
  137. handlers.add(addKeyDownHandler(this));
  138. }
  139. @Override
  140. protected void onDetach() {
  141. for (HandlerRegistration handler : handlers) {
  142. handler.removeHandler();
  143. }
  144. handlers.clear();
  145. super.onDetach();
  146. }
  147. public int getSlotIndex(Element slotElement) {
  148. for (int i = 0; i < slotElements.length; i++) {
  149. if (slotElement == slotElements[i]) {
  150. return i;
  151. }
  152. }
  153. throw new IllegalArgumentException("Element not found in this DateCell");
  154. }
  155. public DateCellSlot getSlot(int index) {
  156. return slots.get(index);
  157. }
  158. public int getNumberOfSlots() {
  159. return numberOfSlots;
  160. }
  161. public void setTimeBarWidth(int timebarWidth) {
  162. todaybar.getStyle().setWidth(timebarWidth, Unit.PX);
  163. }
  164. /**
  165. * @param isHorizontalSized
  166. * if true, this DateCell is sized with CSS and not via
  167. * {@link #setWidthPX(int)}
  168. */
  169. public void setHorizontalSized(boolean isHorizontalSized) {
  170. if (isHorizontalSized) {
  171. addStyleDependentName("Hsized");
  172. width = getOffsetWidth()
  173. - WidgetUtil.measureHorizontalBorder(getElement());
  174. // Update moveWidth for any DateCellDayEvent child
  175. updateEventCellsWidth();
  176. recalculateEventWidths();
  177. } else {
  178. removeStyleDependentName("Hsized");
  179. }
  180. }
  181. /**
  182. * @param isVerticalSized
  183. * if true, this DateCell is sized with CSS and not via
  184. * {@link #setHeightPX(int)}
  185. */
  186. public void setVerticalSized(boolean isVerticalSized) {
  187. if (isVerticalSized) {
  188. addStyleDependentName("Vsized");
  189. // recalc heights&size for events. all other height sizes come
  190. // from css
  191. startingSlotHeight = slotElements[0].getOffsetHeight();
  192. // Update slotHeight for each DateCellDayEvent child
  193. updateEventCellsHeight();
  194. recalculateEventPositions();
  195. if (isToday()) {
  196. recalculateTimeBarPosition();
  197. }
  198. } else {
  199. removeStyleDependentName("Vsized");
  200. }
  201. }
  202. public void setDate(Date date) {
  203. this.date = date;
  204. }
  205. public void setWidthPX(int cellWidth) {
  206. width = cellWidth;
  207. setWidth(cellWidth + "px");
  208. recalculateEventWidths();
  209. }
  210. public void setHeightPX(int height, int[] cellHeights) {
  211. this.height = height;
  212. slotElementHeights = cellHeights;
  213. setHeight(height + "px");
  214. recalculateCellHeights();
  215. recalculateEventPositions();
  216. if (today != null) {
  217. recalculateTimeBarPosition();
  218. }
  219. }
  220. // date methods are not deprecated in GWT
  221. @SuppressWarnings("deprecation")
  222. private void recalculateTimeBarPosition() {
  223. int h = today.getHours();
  224. int m = today.getMinutes();
  225. if (h >= firstHour && h <= lastHour) {
  226. int pixelTop = weekgrid.getPixelTopFor(m + 60 * h);
  227. todaybar.getStyle().clearDisplay();
  228. todaybar.getStyle().setTop(pixelTop, Unit.PX);
  229. } else {
  230. todaybar.getStyle().setDisplay(Display.NONE);
  231. }
  232. }
  233. private void recalculateEventPositions() {
  234. for (int i = 0; i < getWidgetCount(); i++) {
  235. DateCellDayEvent dayEvent = (DateCellDayEvent) getWidget(i);
  236. updatePositionFor(dayEvent, getDate(), dayEvent.getCalendarEvent());
  237. }
  238. }
  239. public void recalculateEventWidths() {
  240. List<DateCellGroup> groups = new ArrayList<DateCellGroup>();
  241. int count = getWidgetCount();
  242. List<Integer> handled = new ArrayList<Integer>();
  243. // Iterate through all events and group them. Events that overlaps
  244. // with each other, are added to the same group.
  245. for (int i = 0; i < count; i++) {
  246. if (handled.contains(i)) {
  247. continue;
  248. }
  249. DateCellGroup curGroup = getOverlappingEvents(i);
  250. handled.addAll(curGroup.getItems());
  251. boolean newGroup = true;
  252. // No need to check other groups, if size equals the count
  253. if (curGroup.getItems().size() != count) {
  254. // Check other groups. When the whole group overlaps with
  255. // other group, the group is merged to the other.
  256. for (DateCellGroup g : groups) {
  257. if (WeekGridMinuteTimeRange.doesOverlap(
  258. curGroup.getDateRange(), g.getDateRange())) {
  259. newGroup = false;
  260. updateGroup(g, curGroup);
  261. }
  262. }
  263. } else {
  264. if (newGroup) {
  265. groups.add(curGroup);
  266. }
  267. break;
  268. }
  269. if (newGroup) {
  270. groups.add(curGroup);
  271. }
  272. }
  273. drawDayEvents(groups);
  274. }
  275. private void recalculateCellHeights() {
  276. startingSlotHeight = height / numberOfSlots;
  277. for (int i = 0; i < slotElements.length; i++) {
  278. slotElements[i].getStyle()
  279. .setHeight(slotElementHeights[i], Unit.PX);
  280. }
  281. updateEventCellsHeight();
  282. }
  283. public int getSlotHeight() {
  284. return startingSlotHeight;
  285. }
  286. public int getSlotBorder() {
  287. return WidgetUtil.measureVerticalBorder(slotElements[0]);
  288. }
  289. private void drawDayEvents(List<DateCellGroup> groups) {
  290. for (DateCellGroup g : groups) {
  291. int col = 0;
  292. int colCount = 0;
  293. List<Integer> order = new ArrayList<Integer>();
  294. Map<Integer, Integer> columns = new HashMap<Integer, Integer>();
  295. for (Integer eventIndex : g.getItems()) {
  296. DateCellDayEvent d = (DateCellDayEvent) getWidget(eventIndex);
  297. d.setMoveWidth(width);
  298. int freeSpaceCol = findFreeColumnSpaceOnLeft(
  299. new WeekGridMinuteTimeRange(d.getCalendarEvent()
  300. .getStartTime(), d.getCalendarEvent()
  301. .getEndTime()), order, columns);
  302. if (freeSpaceCol >= 0) {
  303. col = freeSpaceCol;
  304. columns.put(eventIndex, col);
  305. int newOrderindex = 0;
  306. for (Integer i : order) {
  307. if (columns.get(i) >= col) {
  308. newOrderindex = order.indexOf(i);
  309. break;
  310. }
  311. }
  312. order.add(newOrderindex, eventIndex);
  313. } else {
  314. // New column
  315. col = colCount++;
  316. columns.put(eventIndex, col);
  317. order.add(eventIndex);
  318. }
  319. }
  320. // Update widths and left position
  321. int eventWidth = (width / colCount);
  322. for (Integer index : g.getItems()) {
  323. DateCellDayEvent d = (DateCellDayEvent) getWidget(index);
  324. d.getElement()
  325. .getStyle()
  326. .setMarginLeft((eventWidth * columns.get(index)),
  327. Unit.PX);
  328. d.setWidth(eventWidth + "px");
  329. d.setSlotHeightInPX(getSlotHeight());
  330. }
  331. }
  332. }
  333. private int findFreeColumnSpaceOnLeft(WeekGridMinuteTimeRange dateRange,
  334. List<Integer> order, Map<Integer, Integer> columns) {
  335. int freeSpot = -1;
  336. int skipIndex = -1;
  337. for (Integer eventIndex : order) {
  338. int col = columns.get(eventIndex);
  339. if (col == skipIndex) {
  340. continue;
  341. }
  342. if (freeSpot != -1 && freeSpot != col) {
  343. // Free spot found
  344. return freeSpot;
  345. }
  346. DateCellDayEvent d = (DateCellDayEvent) getWidget(eventIndex);
  347. WeekGridMinuteTimeRange nextRange = new WeekGridMinuteTimeRange(d
  348. .getCalendarEvent().getStartTime(), d.getCalendarEvent()
  349. .getEndTime());
  350. if (WeekGridMinuteTimeRange.doesOverlap(dateRange, nextRange)) {
  351. skipIndex = col;
  352. freeSpot = -1;
  353. } else {
  354. freeSpot = col;
  355. }
  356. }
  357. return freeSpot;
  358. }
  359. /* Update top and bottom date range values. Add new index to the group. */
  360. private void updateGroup(DateCellGroup targetGroup, DateCellGroup byGroup) {
  361. Date newStart = targetGroup.getStart();
  362. Date newEnd = targetGroup.getEnd();
  363. if (byGroup.getStart().before(targetGroup.getStart())) {
  364. newStart = byGroup.getEnd();
  365. }
  366. if (byGroup.getStart().after(targetGroup.getEnd())) {
  367. newStart = byGroup.getStart();
  368. }
  369. targetGroup.setDateRange(new WeekGridMinuteTimeRange(newStart, newEnd));
  370. for (Integer index : byGroup.getItems()) {
  371. if (!targetGroup.getItems().contains(index)) {
  372. targetGroup.add(index);
  373. }
  374. }
  375. }
  376. /**
  377. * Returns all overlapping DayEvent indexes in the Group. Including the
  378. * target.
  379. *
  380. * @param targetIndex
  381. * Index of DayEvent in the current DateCell widget.
  382. * @return Group that contains all Overlapping DayEvent indexes
  383. */
  384. public DateCellGroup getOverlappingEvents(int targetIndex) {
  385. DateCellGroup g = new DateCellGroup(targetIndex);
  386. int count = getWidgetCount();
  387. DateCellDayEvent target = (DateCellDayEvent) getWidget(targetIndex);
  388. WeekGridMinuteTimeRange targetRange = new WeekGridMinuteTimeRange(
  389. target.getCalendarEvent().getStartTime(), target
  390. .getCalendarEvent().getEndTime());
  391. Date groupStart = targetRange.getStart();
  392. Date groupEnd = targetRange.getEnd();
  393. for (int i = 0; i < count; i++) {
  394. if (targetIndex == i) {
  395. continue;
  396. }
  397. DateCellDayEvent d = (DateCellDayEvent) getWidget(i);
  398. WeekGridMinuteTimeRange nextRange = new WeekGridMinuteTimeRange(d
  399. .getCalendarEvent().getStartTime(), d.getCalendarEvent()
  400. .getEndTime());
  401. if (WeekGridMinuteTimeRange.doesOverlap(targetRange, nextRange)) {
  402. g.add(i);
  403. // Update top & bottom values to the greatest
  404. if (nextRange.getStart().before(targetRange.getStart())) {
  405. groupStart = targetRange.getStart();
  406. }
  407. if (nextRange.getEnd().after(targetRange.getEnd())) {
  408. groupEnd = targetRange.getEnd();
  409. }
  410. }
  411. }
  412. g.setDateRange(new WeekGridMinuteTimeRange(groupStart, groupEnd));
  413. return g;
  414. }
  415. public Date getDate() {
  416. return date;
  417. }
  418. public void addEvent(Date targetDay, CalendarEvent calendarEvent) {
  419. Element main = getElement();
  420. DateCellDayEvent dayEvent = new DateCellDayEvent(this, weekgrid,
  421. calendarEvent);
  422. dayEvent.setSlotHeightInPX(getSlotHeight());
  423. dayEvent.setDisabled(isDisabled());
  424. if (startingSlotHeight > 0) {
  425. updatePositionFor(dayEvent, targetDay, calendarEvent);
  426. }
  427. add(dayEvent, main);
  428. }
  429. // date methods are not deprecated in GWT
  430. @SuppressWarnings("deprecation")
  431. private void updatePositionFor(DateCellDayEvent dayEvent, Date targetDay,
  432. CalendarEvent calendarEvent) {
  433. if (shouldDisplay(calendarEvent)) {
  434. dayEvent.getElement().getStyle().clearDisplay();
  435. Date fromDt = calendarEvent.getStartTime();
  436. int h = fromDt.getHours();
  437. int m = fromDt.getMinutes();
  438. long range = calendarEvent.getRangeInMinutesForDay(targetDay);
  439. boolean onDifferentDays = calendarEvent.isTimeOnDifferentDays();
  440. if (onDifferentDays) {
  441. if (calendarEvent.getStart().compareTo(targetDay) != 0) {
  442. // Current day slot is for the end date and all in-between
  443. // days. Lets fix also the start & end times.
  444. h = 0;
  445. m = 0;
  446. }
  447. }
  448. int startFromMinutes = (h * 60) + m;
  449. dayEvent.updatePosition(startFromMinutes, range);
  450. } else {
  451. dayEvent.getElement().getStyle().setDisplay(Display.NONE);
  452. }
  453. }
  454. public void addEvent(DateCellDayEvent dayEvent) {
  455. Element main = getElement();
  456. int index = 0;
  457. List<CalendarEvent> events = new ArrayList<CalendarEvent>();
  458. // events are the only widgets in this panel
  459. // slots are just elements
  460. for (; index < getWidgetCount(); index++) {
  461. DateCellDayEvent dc = (DateCellDayEvent) getWidget(index);
  462. dc.setDisabled(isDisabled());
  463. events.add(dc.getCalendarEvent());
  464. }
  465. events.add(dayEvent.getCalendarEvent());
  466. index = 0;
  467. for (CalendarEvent e : weekgrid.getCalendar().sortEventsByDuration(
  468. events)) {
  469. if (e.equals(dayEvent.getCalendarEvent())) {
  470. break;
  471. }
  472. index++;
  473. }
  474. this.insert(dayEvent, main, index, true);
  475. }
  476. public void removeEvent(DateCellDayEvent dayEvent) {
  477. remove(dayEvent);
  478. }
  479. /**
  480. *
  481. * @param event
  482. * @return
  483. *
  484. * This method is not necessary in the long run.. Or here can be
  485. * various types of implementations..
  486. */
  487. // Date methods not deprecated in GWT
  488. @SuppressWarnings("deprecation")
  489. private boolean shouldDisplay(CalendarEvent event) {
  490. boolean display = true;
  491. if (event.isTimeOnDifferentDays()) {
  492. display = true;
  493. } else { // only in case of one-day event we are able not to display
  494. // event
  495. // which is placed in unpublished parts on calendar
  496. Date eventStart = event.getStartTime();
  497. Date eventEnd = event.getEndTime();
  498. int eventStartHours = eventStart.getHours();
  499. int eventEndHours = eventEnd.getHours();
  500. display = !(eventEndHours < firstHour || eventStartHours > lastHour);
  501. }
  502. return display;
  503. }
  504. @Override
  505. public void onKeyDown(KeyDownEvent event) {
  506. int keycode = event.getNativeEvent().getKeyCode();
  507. if (keycode == KeyCodes.KEY_ESCAPE && eventRangeStart > -1) {
  508. cancelRangeSelect();
  509. }
  510. }
  511. @Override
  512. public void onMouseDown(MouseDownEvent event) {
  513. if (event.getNativeButton() == NativeEvent.BUTTON_LEFT) {
  514. Element e = Element.as(event.getNativeEvent().getEventTarget());
  515. if (e.getClassName().contains("reserved") || isDisabled()
  516. || !weekgrid.getParentCalendar().isRangeSelectAllowed()) {
  517. eventRangeStart = -1;
  518. } else {
  519. eventRangeStart = event.getY();
  520. eventRangeStop = eventRangeStart;
  521. Event.setCapture(getElement());
  522. setFocus(true);
  523. }
  524. }
  525. }
  526. @Override
  527. @SuppressWarnings("deprecation")
  528. public void onMouseUp(MouseUpEvent event) {
  529. if (event.getNativeButton() != NativeEvent.BUTTON_LEFT) {
  530. return;
  531. }
  532. Event.releaseCapture(getElement());
  533. setFocus(false);
  534. int dragDistance = Math.abs(eventRangeStart - event.getY());
  535. if (dragDistance > 0 && eventRangeStart >= 0) {
  536. Element main = getElement();
  537. if (eventRangeStart > eventRangeStop) {
  538. if (eventRangeStop <= -1) {
  539. eventRangeStop = 0;
  540. }
  541. int temp = eventRangeStart;
  542. eventRangeStart = eventRangeStop;
  543. eventRangeStop = temp;
  544. }
  545. NodeList<Node> nodes = main.getChildNodes();
  546. int slotStart = -1;
  547. int slotEnd = -1;
  548. // iterate over all child nodes, until we find first the start,
  549. // and then the end
  550. for (int i = 0; i < nodes.getLength(); i++) {
  551. Element element = (Element) nodes.getItem(i);
  552. boolean isRangeElement = element.getClassName().contains(
  553. "v-daterange");
  554. if (isRangeElement && slotStart == -1) {
  555. slotStart = i;
  556. slotEnd = i; // to catch one-slot selections
  557. } else if (isRangeElement) {
  558. slotEnd = i;
  559. } else if (slotStart != -1 && slotEnd != -1) {
  560. break;
  561. }
  562. }
  563. clearSelectionRange();
  564. int startMinutes = firstHour * 60 + slotStart * 30;
  565. int endMinutes = (firstHour * 60) + (slotEnd + 1) * 30;
  566. Date currentDate = getDate();
  567. String yr = (currentDate.getYear() + 1900) + "-"
  568. + (currentDate.getMonth() + 1) + "-"
  569. + currentDate.getDate();
  570. if (weekgrid.getCalendar().getRangeSelectListener() != null) {
  571. weekgrid.getCalendar()
  572. .getRangeSelectListener()
  573. .rangeSelected(
  574. yr + ":" + startMinutes + ":" + endMinutes);
  575. }
  576. eventRangeStart = -1;
  577. } else {
  578. // Click event
  579. eventRangeStart = -1;
  580. cancelRangeSelect();
  581. }
  582. }
  583. @Override
  584. public void onMouseMove(MouseMoveEvent event) {
  585. if (event.getNativeButton() != NativeEvent.BUTTON_LEFT) {
  586. return;
  587. }
  588. if (eventRangeStart >= 0) {
  589. int newY = event.getY();
  590. int fromY = 0;
  591. int toY = 0;
  592. if (newY < eventRangeStart) {
  593. fromY = newY;
  594. toY = eventRangeStart;
  595. } else {
  596. fromY = eventRangeStart;
  597. toY = newY;
  598. }
  599. Element main = getElement();
  600. eventRangeStop = newY;
  601. NodeList<Node> nodes = main.getChildNodes();
  602. for (int i = 0; i < nodes.getLength(); i++) {
  603. Element c = (Element) nodes.getItem(i);
  604. if (todaybar != c) {
  605. int elemStart = c.getOffsetTop();
  606. int elemStop = elemStart + getSlotHeight();
  607. if (elemStart >= fromY && elemStart <= toY) {
  608. c.addClassName("v-daterange");
  609. } else if (elemStop >= fromY && elemStop <= toY) {
  610. c.addClassName("v-daterange");
  611. } else if (elemStop >= fromY && elemStart <= toY) {
  612. c.addClassName("v-daterange");
  613. } else {
  614. c.removeClassName("v-daterange");
  615. }
  616. }
  617. }
  618. }
  619. event.preventDefault();
  620. }
  621. public void cancelRangeSelect() {
  622. Event.releaseCapture(getElement());
  623. setFocus(false);
  624. clearSelectionRange();
  625. }
  626. private void clearSelectionRange() {
  627. if (eventRangeStart > -1) {
  628. // clear all "selected" class names
  629. Element main = getElement();
  630. NodeList<Node> nodes = main.getChildNodes();
  631. for (int i = 0; i <= 47; i++) {
  632. Element c = (Element) nodes.getItem(i);
  633. if (c == null) {
  634. continue;
  635. }
  636. c.removeClassName("v-daterange");
  637. }
  638. eventRangeStart = -1;
  639. }
  640. }
  641. public void setToday(Date today, int width) {
  642. this.today = today;
  643. addStyleDependentName("today");
  644. Element lastChild = (Element) getElement().getLastChild();
  645. if (lastChild.getClassName().equals("v-calendar-current-time")) {
  646. todaybar = lastChild;
  647. } else {
  648. todaybar = DOM.createDiv();
  649. todaybar.setClassName("v-calendar-current-time");
  650. getElement().appendChild(todaybar);
  651. }
  652. if (width != -1) {
  653. todaybar.getStyle().setWidth(width, Unit.PX);
  654. }
  655. // position is calculated later, when we know the cell heights
  656. }
  657. public Element getTodaybarElement() {
  658. return todaybar;
  659. }
  660. public void setDisabled(boolean disabled) {
  661. this.disabled = disabled;
  662. }
  663. public boolean isDisabled() {
  664. return disabled;
  665. }
  666. public void setDateColor(String styleName) {
  667. this.setStyleName("v-calendar-datecell " + styleName);
  668. }
  669. public boolean isToday() {
  670. return today != null;
  671. }
  672. /**
  673. * @deprecated As of 7.2, call or override
  674. * {@link #addEmphasisStyle(Element)} instead
  675. */
  676. @Deprecated
  677. public void addEmphasisStyle(com.google.gwt.user.client.Element elementOver) {
  678. String originalStylename = getStyleName(elementOver);
  679. setStyleName(elementOver, originalStylename + DRAGEMPHASISSTYLE);
  680. }
  681. /**
  682. * @since 7.2
  683. */
  684. public void addEmphasisStyle(Element elementOver) {
  685. addEmphasisStyle(DOM.asOld(elementOver));
  686. }
  687. /**
  688. * @deprecated As of 7.2, call or override
  689. * {@link #removeEmphasisStyle(Element)} instead
  690. */
  691. @Deprecated
  692. public void removeEmphasisStyle(
  693. com.google.gwt.user.client.Element elementOver) {
  694. String originalStylename = getStyleName(elementOver);
  695. setStyleName(
  696. elementOver,
  697. originalStylename.substring(0, originalStylename.length()
  698. - DRAGEMPHASISSTYLE.length()));
  699. }
  700. /**
  701. * @since 7.2
  702. */
  703. public void removeEmphasisStyle(Element elementOver) {
  704. removeEmphasisStyle(DOM.asOld(elementOver));
  705. }
  706. @Override
  707. public void onContextMenu(ContextMenuEvent event) {
  708. if (weekgrid.getCalendar().getMouseEventListener() != null) {
  709. event.preventDefault();
  710. event.stopPropagation();
  711. weekgrid.getCalendar().getMouseEventListener()
  712. .contextMenu(event, DateCell.this);
  713. }
  714. }
  715. private void updateEventCellsWidth() {
  716. for (Widget widget : getChildren()) {
  717. if (widget instanceof DateCellDayEvent) {
  718. ((DateCellDayEvent) widget).setMoveWidth(width);
  719. }
  720. }
  721. }
  722. private void updateEventCellsHeight() {
  723. for (Widget widget : getChildren()) {
  724. if (widget instanceof DateCellDayEvent) {
  725. ((DateCellDayEvent) widget).setSlotHeightInPX(getSlotHeight());
  726. }
  727. }
  728. }
  729. }