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.

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153
  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.v7.ui;
  17. import java.lang.reflect.Method;
  18. import java.text.DateFormat;
  19. import java.text.DateFormatSymbols;
  20. import java.text.ParseException;
  21. import java.text.SimpleDateFormat;
  22. import java.util.ArrayList;
  23. import java.util.Arrays;
  24. import java.util.Collection;
  25. import java.util.Date;
  26. import java.util.EventListener;
  27. import java.util.GregorianCalendar;
  28. import java.util.HashMap;
  29. import java.util.LinkedHashSet;
  30. import java.util.LinkedList;
  31. import java.util.List;
  32. import java.util.Locale;
  33. import java.util.Map;
  34. import java.util.Map.Entry;
  35. import java.util.Set;
  36. import java.util.TimeZone;
  37. import java.util.logging.Level;
  38. import java.util.logging.Logger;
  39. import org.jsoup.nodes.Attributes;
  40. import org.jsoup.nodes.Element;
  41. import com.vaadin.event.Action;
  42. import com.vaadin.event.Action.Handler;
  43. import com.vaadin.event.dd.DropHandler;
  44. import com.vaadin.event.dd.DropTarget;
  45. import com.vaadin.event.dd.TargetDetails;
  46. import com.vaadin.server.KeyMapper;
  47. import com.vaadin.server.PaintException;
  48. import com.vaadin.server.PaintTarget;
  49. import com.vaadin.ui.LegacyComponent;
  50. import com.vaadin.ui.declarative.DesignAttributeHandler;
  51. import com.vaadin.ui.declarative.DesignContext;
  52. import com.vaadin.v7.data.Container;
  53. import com.vaadin.v7.data.util.BeanItemContainer;
  54. import com.vaadin.v7.shared.ui.calendar.CalendarEventId;
  55. import com.vaadin.v7.shared.ui.calendar.CalendarServerRpc;
  56. import com.vaadin.v7.shared.ui.calendar.CalendarState;
  57. import com.vaadin.v7.shared.ui.calendar.CalendarState.EventSortOrder;
  58. import com.vaadin.v7.shared.ui.calendar.DateConstants;
  59. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvent;
  60. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents;
  61. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.BackwardEvent;
  62. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.BackwardHandler;
  63. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.DateClickEvent;
  64. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.DateClickHandler;
  65. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventClick;
  66. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventClickHandler;
  67. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventMoveHandler;
  68. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventResize;
  69. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventResizeHandler;
  70. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.ForwardEvent;
  71. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.ForwardHandler;
  72. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.MoveEvent;
  73. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.RangeSelectEvent;
  74. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.RangeSelectHandler;
  75. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.WeekClick;
  76. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.WeekClickHandler;
  77. import com.vaadin.v7.ui.components.calendar.CalendarDateRange;
  78. import com.vaadin.v7.ui.components.calendar.CalendarTargetDetails;
  79. import com.vaadin.v7.ui.components.calendar.ContainerEventProvider;
  80. import com.vaadin.v7.ui.components.calendar.event.BasicEventProvider;
  81. import com.vaadin.v7.ui.components.calendar.event.CalendarEditableEventProvider;
  82. import com.vaadin.v7.ui.components.calendar.event.CalendarEvent;
  83. import com.vaadin.v7.ui.components.calendar.event.CalendarEvent.EventChangeEvent;
  84. import com.vaadin.v7.ui.components.calendar.event.CalendarEvent.EventChangeListener;
  85. import com.vaadin.v7.ui.components.calendar.event.CalendarEventProvider;
  86. import com.vaadin.v7.ui.components.calendar.handler.BasicBackwardHandler;
  87. import com.vaadin.v7.ui.components.calendar.handler.BasicDateClickHandler;
  88. import com.vaadin.v7.ui.components.calendar.handler.BasicEventMoveHandler;
  89. import com.vaadin.v7.ui.components.calendar.handler.BasicEventResizeHandler;
  90. import com.vaadin.v7.ui.components.calendar.handler.BasicForwardHandler;
  91. import com.vaadin.v7.ui.components.calendar.handler.BasicWeekClickHandler;
  92. /**
  93. * <p>
  94. * Vaadin Calendar is for visualizing events in a calendar. Calendar events can
  95. * be visualized in the variable length view depending on the start and end
  96. * dates.
  97. * </p>
  98. *
  99. * <li>You can set the viewable date range with the {@link #setStartDate(Date)}
  100. * and {@link #setEndDate(Date)} methods. Calendar has a default date range of
  101. * one week</li>
  102. *
  103. * <li>Calendar has two kind of views: monthly and weekly view</li>
  104. *
  105. * <li>If date range is seven days or shorter, the weekly view is used.</li>
  106. *
  107. * <li>Calendar queries its events by using a
  108. * {@link com.vaadin.addon.calendar.event.CalendarEventProvider
  109. * CalendarEventProvider}. By default, a
  110. * {@link com.vaadin.addon.calendar.event.BasicEventProvider BasicEventProvider}
  111. * is used.</li>
  112. *
  113. * @since 7.1
  114. * @author Vaadin Ltd.
  115. */
  116. @SuppressWarnings("serial")
  117. @Deprecated
  118. public class Calendar extends AbstractLegacyComponent
  119. implements CalendarComponentEvents.NavigationNotifier,
  120. CalendarComponentEvents.EventMoveNotifier,
  121. CalendarComponentEvents.RangeSelectNotifier,
  122. CalendarComponentEvents.EventResizeNotifier,
  123. CalendarEventProvider.EventSetChangeListener, DropTarget,
  124. CalendarEditableEventProvider, Action.Container, LegacyComponent {
  125. /**
  126. * Calendar can use either 12 hours clock or 24 hours clock.
  127. */
  128. @Deprecated
  129. public enum TimeFormat {
  130. Format12H(), Format24H();
  131. }
  132. /** Defines currently active format for time. 12H/24H. */
  133. protected TimeFormat currentTimeFormat;
  134. /** Internal calendar data source. */
  135. protected java.util.Calendar currentCalendar = java.util.Calendar
  136. .getInstance();
  137. /** Defines the component's active time zone. */
  138. protected TimeZone timezone;
  139. /** Defines the calendar's date range starting point. */
  140. protected Date startDate = null;
  141. /** Defines the calendar's date range ending point. */
  142. protected Date endDate = null;
  143. /** Event provider. */
  144. private CalendarEventProvider calendarEventProvider;
  145. /**
  146. * Internal buffer for the events that are retrieved from the event
  147. * provider.
  148. */
  149. protected List<CalendarEvent> events;
  150. /** Date format that will be used in the UIDL for dates. */
  151. protected DateFormat df_date = new SimpleDateFormat("yyyy-MM-dd");
  152. /** Time format that will be used in the UIDL for time. */
  153. protected DateFormat df_time = new SimpleDateFormat("HH:mm:ss");
  154. /** Date format that will be used in the UIDL for both date and time. */
  155. protected DateFormat df_date_time = new SimpleDateFormat(
  156. DateConstants.CLIENT_DATE_FORMAT + "-"
  157. + DateConstants.CLIENT_TIME_FORMAT);
  158. /**
  159. * Week view's scroll position. Client sends updates to this value so that
  160. * scroll position wont reset all the time.
  161. */
  162. private int scrollTop = 0;
  163. /** Caption format for the weekly view */
  164. private String weeklyCaptionFormat = null;
  165. /** Map from event ids to event handlers */
  166. private final Map<String, EventListener> handlers;
  167. /**
  168. * Drop Handler for Vaadin DD. By default null.
  169. */
  170. private DropHandler dropHandler;
  171. /**
  172. * First day to show for a week
  173. */
  174. private int firstDay = 1;
  175. /**
  176. * Last day to show for a week
  177. */
  178. private int lastDay = 7;
  179. /**
  180. * First hour to show for a day
  181. */
  182. private int firstHour = 0;
  183. /**
  184. * Last hour to show for a day
  185. */
  186. private int lastHour = 23;
  187. /**
  188. * List of action handlers.
  189. */
  190. private LinkedList<Action.Handler> actionHandlers = null;
  191. /**
  192. * Action mapper.
  193. */
  194. private KeyMapper<Action> actionMapper = null;
  195. /**
  196. *
  197. */
  198. private CalendarServerRpcImpl rpc = new CalendarServerRpcImpl();
  199. /**
  200. * The cached minimum minute shown when using
  201. * {@link #autoScaleVisibleHoursOfDay()}.
  202. */
  203. private Integer minTimeInMinutes;
  204. /**
  205. * The cached maximum minute shown when using
  206. * {@link #autoScaleVisibleHoursOfDay()}.
  207. */
  208. private Integer maxTimeInMinutes;
  209. private Integer customFirstDayOfWeek;
  210. /**
  211. * Returns the logger for the calendar
  212. */
  213. protected Logger getLogger() {
  214. return Logger.getLogger(Calendar.class.getName());
  215. }
  216. /**
  217. * Construct a Vaadin Calendar with a BasicEventProvider and no caption.
  218. * Default date range is one week.
  219. */
  220. public Calendar() {
  221. this(null, new BasicEventProvider());
  222. }
  223. /**
  224. * Construct a Vaadin Calendar with a BasicEventProvider and the provided
  225. * caption. Default date range is one week.
  226. *
  227. * @param caption
  228. */
  229. public Calendar(String caption) {
  230. this(caption, new BasicEventProvider());
  231. }
  232. /**
  233. * <p>
  234. * Construct a Vaadin Calendar with event provider. Event provider is
  235. * obligatory, because calendar component will query active events through
  236. * it.
  237. * </p>
  238. *
  239. * <p>
  240. * By default, Vaadin Calendar will show dates from the start of the current
  241. * week to the end of the current week. Use {@link #setStartDate(Date)} and
  242. * {@link #setEndDate(Date)} to change this.
  243. * </p>
  244. *
  245. * @param eventProvider
  246. * Event provider, cannot be null.
  247. */
  248. public Calendar(CalendarEventProvider eventProvider) {
  249. this(null, eventProvider);
  250. }
  251. /**
  252. * <p>
  253. * Construct a Vaadin Calendar with event provider and a caption. Event
  254. * provider is obligatory, because calendar component will query active
  255. * events through it.
  256. * </p>
  257. *
  258. * <p>
  259. * By default, Vaadin Calendar will show dates from the start of the current
  260. * week to the end of the current week. Use {@link #setStartDate(Date)} and
  261. * {@link #setEndDate(Date)} to change this.
  262. * </p>
  263. *
  264. * @param eventProvider
  265. * Event provider, cannot be null.
  266. */
  267. // this is the constructor every other constructor calls
  268. public Calendar(String caption, CalendarEventProvider eventProvider) {
  269. registerRpc(rpc);
  270. setCaption(caption);
  271. handlers = new HashMap<>();
  272. setDefaultHandlers();
  273. currentCalendar.setTime(new Date());
  274. setEventProvider(eventProvider);
  275. getState().firstDayOfWeek = firstDay;
  276. getState().lastVisibleDayOfWeek = lastDay;
  277. getState().firstHourOfDay = firstHour;
  278. getState().lastHourOfDay = lastHour;
  279. setTimeFormat(null);
  280. }
  281. @Override
  282. public CalendarState getState() {
  283. return (CalendarState) super.getState();
  284. }
  285. @Override
  286. protected CalendarState getState(boolean markAsDirty) {
  287. return (CalendarState) super.getState(markAsDirty);
  288. }
  289. @Override
  290. public void beforeClientResponse(boolean initial) {
  291. super.beforeClientResponse(initial);
  292. initCalendarWithLocale();
  293. getState().format24H = TimeFormat.Format24H == getTimeFormat();
  294. setupDaysAndActions();
  295. setupCalendarEvents();
  296. rpc.scroll(scrollTop);
  297. }
  298. /**
  299. * Set all the wanted default handlers here. This is always called after
  300. * constructing this object. All other events have default handlers except
  301. * range and event click.
  302. */
  303. protected void setDefaultHandlers() {
  304. setHandler(new BasicBackwardHandler());
  305. setHandler(new BasicForwardHandler());
  306. setHandler(new BasicWeekClickHandler());
  307. setHandler(new BasicDateClickHandler());
  308. setHandler(new BasicEventMoveHandler());
  309. setHandler(new BasicEventResizeHandler());
  310. }
  311. /**
  312. * Gets the calendar's start date.
  313. *
  314. * @return First visible date.
  315. */
  316. public Date getStartDate() {
  317. if (startDate == null) {
  318. currentCalendar.set(java.util.Calendar.MILLISECOND, 0);
  319. currentCalendar.set(java.util.Calendar.SECOND, 0);
  320. currentCalendar.set(java.util.Calendar.MINUTE, 0);
  321. currentCalendar.set(java.util.Calendar.HOUR_OF_DAY, 0);
  322. currentCalendar.set(java.util.Calendar.DAY_OF_WEEK,
  323. currentCalendar.getFirstDayOfWeek());
  324. return currentCalendar.getTime();
  325. }
  326. return startDate;
  327. }
  328. /**
  329. * Sets start date for the calendar. This and {@link #setEndDate(Date)}
  330. * control the range of dates visible on the component. The default range is
  331. * one week.
  332. *
  333. * @param date
  334. * First visible date to show.
  335. */
  336. public void setStartDate(Date date) {
  337. if (!date.equals(startDate)) {
  338. startDate = date;
  339. markAsDirty();
  340. }
  341. }
  342. /**
  343. * Gets the calendar's end date.
  344. *
  345. * @return Last visible date.
  346. */
  347. public Date getEndDate() {
  348. if (endDate == null) {
  349. currentCalendar.set(java.util.Calendar.MILLISECOND, 0);
  350. currentCalendar.set(java.util.Calendar.SECOND, 59);
  351. currentCalendar.set(java.util.Calendar.MINUTE, 59);
  352. currentCalendar.set(java.util.Calendar.HOUR_OF_DAY, 23);
  353. currentCalendar.set(java.util.Calendar.DAY_OF_WEEK,
  354. currentCalendar.getFirstDayOfWeek() + 6);
  355. return currentCalendar.getTime();
  356. }
  357. return endDate;
  358. }
  359. /**
  360. * Sets end date for the calendar. Starting from startDate, only six weeks
  361. * will be shown if duration to endDate is longer than six weeks.
  362. *
  363. * This and {@link #setStartDate(Date)} control the range of dates visible
  364. * on the component. The default range is one week.
  365. *
  366. * @param date
  367. * Last visible date to show.
  368. */
  369. public void setEndDate(Date date) {
  370. if (startDate != null && startDate.after(date)) {
  371. startDate = (Date) date.clone();
  372. markAsDirty();
  373. } else if (!date.equals(endDate)) {
  374. endDate = date;
  375. markAsDirty();
  376. }
  377. }
  378. /**
  379. * Sets the locale to be used in the Calendar component.
  380. *
  381. * @see com.vaadin.ui.AbstractComponent#setLocale(java.util.Locale)
  382. */
  383. @Override
  384. public void setLocale(Locale newLocale) {
  385. super.setLocale(newLocale);
  386. initCalendarWithLocale();
  387. }
  388. /**
  389. * Initialize the java calendar instance with the current locale and
  390. * timezone.
  391. */
  392. private void initCalendarWithLocale() {
  393. if (timezone != null) {
  394. currentCalendar = java.util.Calendar.getInstance(timezone,
  395. getLocale());
  396. } else {
  397. currentCalendar = java.util.Calendar.getInstance(getLocale());
  398. }
  399. if (customFirstDayOfWeek != null) {
  400. currentCalendar.setFirstDayOfWeek(customFirstDayOfWeek);
  401. }
  402. }
  403. private void setupCalendarEvents() {
  404. int durationInDays = (int) ((endDate.getTime() - startDate.getTime())
  405. / DateConstants.DAYINMILLIS);
  406. durationInDays++;
  407. if (durationInDays > 60) {
  408. throw new RuntimeException(
  409. "Daterange is too big (max 60) = " + durationInDays);
  410. }
  411. Date firstDateToShow = expandStartDate(startDate, durationInDays > 7);
  412. Date lastDateToShow = expandEndDate(endDate, durationInDays > 7);
  413. currentCalendar.setTime(firstDateToShow);
  414. events = getEventProvider().getEvents(firstDateToShow, lastDateToShow);
  415. cacheMinMaxTimeOfDay(events);
  416. List<CalendarState.Event> calendarStateEvents = new ArrayList<>();
  417. if (events != null) {
  418. for (int i = 0; i < events.size(); i++) {
  419. CalendarEvent e = events.get(i);
  420. CalendarState.Event event = new CalendarState.Event();
  421. event.index = i;
  422. event.caption = e.getCaption() == null ? "" : e.getCaption();
  423. event.dateFrom = df_date.format(e.getStart());
  424. event.dateTo = df_date.format(e.getEnd());
  425. event.timeFrom = df_time.format(e.getStart());
  426. event.timeTo = df_time.format(e.getEnd());
  427. event.description = e.getDescription() == null ? ""
  428. : e.getDescription();
  429. event.styleName = e.getStyleName() == null ? ""
  430. : e.getStyleName();
  431. event.allDay = e.isAllDay();
  432. calendarStateEvents.add(event);
  433. }
  434. }
  435. getState().events = calendarStateEvents;
  436. }
  437. /**
  438. * Stores the minimum and maximum time-of-day in minutes for the events.
  439. *
  440. * @param events
  441. * A list of calendar events. Can be <code>null</code>.
  442. */
  443. private void cacheMinMaxTimeOfDay(List<CalendarEvent> events) {
  444. minTimeInMinutes = null;
  445. maxTimeInMinutes = null;
  446. if (events != null) {
  447. for (CalendarEvent event : events) {
  448. int minuteOfDayStart = getMinuteOfDay(event.getStart());
  449. int minuteOfDayEnd = getMinuteOfDay(event.getEnd());
  450. if (minTimeInMinutes == null) {
  451. minTimeInMinutes = minuteOfDayStart;
  452. maxTimeInMinutes = minuteOfDayEnd;
  453. } else {
  454. if (minuteOfDayStart < minTimeInMinutes) {
  455. minTimeInMinutes = minuteOfDayStart;
  456. }
  457. if (minuteOfDayEnd > maxTimeInMinutes) {
  458. maxTimeInMinutes = minuteOfDayEnd;
  459. }
  460. }
  461. }
  462. }
  463. }
  464. private static int getMinuteOfDay(Date date) {
  465. java.util.Calendar calendar = java.util.Calendar.getInstance();
  466. calendar.setTime(date);
  467. return calendar.get(java.util.Calendar.HOUR_OF_DAY) * 60
  468. + calendar.get(java.util.Calendar.MINUTE);
  469. }
  470. /**
  471. * Sets the displayed start and end time to fit all current events that were
  472. * retrieved from the last call to getEvents().
  473. * <p>
  474. * If no events exist, nothing happens.
  475. * <p>
  476. * <b>NOTE: triggering this method only does this once for the current
  477. * events - events that are not in the current visible range, are
  478. * ignored!</b>
  479. *
  480. * @see #setFirstVisibleHourOfDay(int)
  481. * @see #setLastVisibleHourOfDay(int)
  482. */
  483. public void autoScaleVisibleHoursOfDay() {
  484. if (minTimeInMinutes != null) {
  485. setFirstVisibleHourOfDay(minTimeInMinutes / 60);
  486. // Do not show the final hour if last minute ends on it
  487. setLastVisibleHourOfDay((maxTimeInMinutes - 1) / 60);
  488. }
  489. }
  490. /**
  491. * Resets the {@link #setFirstVisibleHourOfDay(int)} and
  492. * {@link #setLastVisibleHourOfDay(int)} to the default values, 0 and 23
  493. * respectively.
  494. *
  495. * @see #autoScaleVisibleHoursOfDay()
  496. * @see #setFirstVisibleHourOfDay(int)
  497. * @see #setLastVisibleHourOfDay(int)
  498. */
  499. public void resetVisibleHoursOfDay() {
  500. setFirstVisibleHourOfDay(0);
  501. setLastVisibleHourOfDay(23);
  502. }
  503. private void setupDaysAndActions() {
  504. // Make sure we have a up-to-date locale
  505. initCalendarWithLocale();
  506. CalendarState state = getState();
  507. state.firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
  508. // If only one is null, throw exception
  509. // If both are null, set defaults
  510. if (startDate == null ^ endDate == null) {
  511. String message = "Schedule cannot be painted without a proper date range.\n";
  512. if (startDate == null) {
  513. throw new IllegalStateException(message
  514. + "You must set a start date using setStartDate(Date).");
  515. } else {
  516. throw new IllegalStateException(message
  517. + "You must set an end date using setEndDate(Date).");
  518. }
  519. } else if (startDate == null && endDate == null) {
  520. // set defaults
  521. startDate = getStartDate();
  522. endDate = getEndDate();
  523. }
  524. int durationInDays = (int) ((endDate.getTime() - startDate.getTime())
  525. / DateConstants.DAYINMILLIS);
  526. durationInDays++;
  527. if (durationInDays > 60) {
  528. throw new RuntimeException(
  529. "Daterange is too big (max 60) = " + durationInDays);
  530. }
  531. state.dayNames = getDayNamesShort();
  532. state.monthNames = getMonthNamesShort();
  533. // Use same timezone in all dates this component handles.
  534. // Show "now"-marker in browser within given timezone.
  535. Date now = new Date();
  536. currentCalendar.setTime(now);
  537. now = currentCalendar.getTime();
  538. // Reset time zones for custom date formats
  539. df_date.setTimeZone(currentCalendar.getTimeZone());
  540. df_time.setTimeZone(currentCalendar.getTimeZone());
  541. state.now = df_date.format(now) + " " + df_time.format(now);
  542. Date firstDateToShow = expandStartDate(startDate, durationInDays > 7);
  543. Date lastDateToShow = expandEndDate(endDate, durationInDays > 7);
  544. currentCalendar.setTime(firstDateToShow);
  545. DateFormat weeklyCaptionFormatter = getWeeklyCaptionFormatter();
  546. weeklyCaptionFormatter.setTimeZone(currentCalendar.getTimeZone());
  547. Map<CalendarDateRange, Set<Action>> actionMap = new HashMap<>();
  548. List<CalendarState.Day> days = new ArrayList<>();
  549. // Send all dates to client from server. This
  550. // approach was taken because gwt doesn't
  551. // support date localization properly.
  552. while (currentCalendar.getTime().compareTo(lastDateToShow) < 1) {
  553. final Date date = currentCalendar.getTime();
  554. final CalendarState.Day day = new CalendarState.Day();
  555. day.date = df_date.format(date);
  556. day.localizedDateFormat = weeklyCaptionFormatter.format(date);
  557. day.dayOfWeek = getDowByLocale(currentCalendar);
  558. day.week = getWeek(currentCalendar);
  559. day.yearOfWeek = getYearOfWeek(currentCalendar);
  560. days.add(day);
  561. // Get actions for a specific date
  562. if (actionHandlers != null) {
  563. for (Action.Handler actionHandler : actionHandlers) {
  564. // Create calendar which omits time
  565. GregorianCalendar cal = new GregorianCalendar(getTimeZone(),
  566. getLocale());
  567. cal.clear();
  568. cal.set(currentCalendar.get(java.util.Calendar.YEAR),
  569. currentCalendar.get(java.util.Calendar.MONTH),
  570. currentCalendar.get(java.util.Calendar.DATE));
  571. // Get day start and end times
  572. Date start = cal.getTime();
  573. cal.add(java.util.Calendar.DATE, 1);
  574. cal.add(java.util.Calendar.SECOND, -1);
  575. Date end = cal.getTime();
  576. boolean monthView = durationInDays > 7;
  577. /**
  578. * If in day or week view add actions for each half-an-hour.
  579. * If in month view add actions for each day
  580. */
  581. if (monthView) {
  582. setActionsForDay(actionMap, start, end, actionHandler);
  583. } else {
  584. setActionsForEachHalfHour(actionMap, start, end,
  585. actionHandler);
  586. }
  587. }
  588. }
  589. currentCalendar.add(java.util.Calendar.DATE, 1);
  590. }
  591. state.days = days;
  592. state.actions = createActionsList(actionMap);
  593. }
  594. private int getWeek(java.util.Calendar calendar) {
  595. return calendar.get(java.util.Calendar.WEEK_OF_YEAR);
  596. }
  597. private int getYearOfWeek(java.util.Calendar calendar) {
  598. // Would use calendar.getWeekYear() but it's only available since 1.7.
  599. int week = getWeek(calendar);
  600. int month = calendar.get(java.util.Calendar.MONTH);
  601. int year = calendar.get(java.util.Calendar.YEAR);
  602. if (week == 1 && month == java.util.Calendar.DECEMBER) {
  603. return year + 1;
  604. }
  605. return year;
  606. }
  607. private void setActionsForEachHalfHour(
  608. Map<CalendarDateRange, Set<Action>> actionMap, Date start, Date end,
  609. Action.Handler actionHandler) {
  610. GregorianCalendar cal = new GregorianCalendar(getTimeZone(),
  611. getLocale());
  612. cal.setTime(start);
  613. while (cal.getTime().before(end)) {
  614. Date s = cal.getTime();
  615. cal.add(java.util.Calendar.MINUTE, 30);
  616. Date e = cal.getTime();
  617. CalendarDateRange range = new CalendarDateRange(s, e,
  618. getTimeZone());
  619. Action[] actions = actionHandler.getActions(range, this);
  620. if (actions != null) {
  621. Set<Action> actionSet = new LinkedHashSet<>(
  622. Arrays.asList(actions));
  623. actionMap.put(range, actionSet);
  624. }
  625. }
  626. }
  627. private void setActionsForDay(Map<CalendarDateRange, Set<Action>> actionMap,
  628. Date start, Date end, Action.Handler actionHandler) {
  629. CalendarDateRange range = new CalendarDateRange(start, end,
  630. getTimeZone());
  631. Action[] actions = actionHandler.getActions(range, this);
  632. if (actions != null) {
  633. Set<Action> actionSet = new LinkedHashSet<>(Arrays.asList(actions));
  634. actionMap.put(range, actionSet);
  635. }
  636. }
  637. private List<CalendarState.Action> createActionsList(
  638. Map<CalendarDateRange, Set<Action>> actionMap) {
  639. if (actionMap.isEmpty()) {
  640. return null;
  641. }
  642. List<CalendarState.Action> calendarActions = new ArrayList<>();
  643. SimpleDateFormat formatter = new SimpleDateFormat(
  644. DateConstants.ACTION_DATE_FORMAT_PATTERN);
  645. formatter.setTimeZone(getTimeZone());
  646. for (Entry<CalendarDateRange, Set<Action>> entry : actionMap
  647. .entrySet()) {
  648. CalendarDateRange range = entry.getKey();
  649. Set<Action> actions = entry.getValue();
  650. for (Action action : actions) {
  651. String key = actionMapper.key(action);
  652. CalendarState.Action calendarAction = new CalendarState.Action();
  653. calendarAction.actionKey = key;
  654. calendarAction.caption = action.getCaption();
  655. setResource(key, action.getIcon());
  656. calendarAction.iconKey = key;
  657. calendarAction.startDate = formatter.format(range.getStart());
  658. calendarAction.endDate = formatter.format(range.getEnd());
  659. calendarActions.add(calendarAction);
  660. }
  661. }
  662. return calendarActions;
  663. }
  664. /**
  665. * Gets currently active time format. Value is either TimeFormat.Format12H
  666. * or TimeFormat.Format24H.
  667. *
  668. * @return TimeFormat Format for the time.
  669. */
  670. public TimeFormat getTimeFormat() {
  671. if (currentTimeFormat == null) {
  672. SimpleDateFormat f;
  673. if (getLocale() == null) {
  674. f = (SimpleDateFormat) SimpleDateFormat
  675. .getTimeInstance(SimpleDateFormat.SHORT);
  676. } else {
  677. f = (SimpleDateFormat) SimpleDateFormat
  678. .getTimeInstance(SimpleDateFormat.SHORT, getLocale());
  679. }
  680. String p = f.toPattern();
  681. if (p.indexOf("HH") != -1 || p.indexOf("H") != -1) {
  682. return TimeFormat.Format24H;
  683. }
  684. return TimeFormat.Format12H;
  685. }
  686. return currentTimeFormat;
  687. }
  688. /**
  689. * Example: <code>setTimeFormat(TimeFormat.Format12H);</code></br>
  690. * Set to null, if you want the format being defined by the locale.
  691. *
  692. * @param format
  693. * Set 12h or 24h format. Default is defined by the locale.
  694. */
  695. public void setTimeFormat(TimeFormat format) {
  696. currentTimeFormat = format;
  697. markAsDirty();
  698. }
  699. /**
  700. * Returns a time zone that is currently used by this component.
  701. *
  702. * @return Component's Time zone
  703. */
  704. public TimeZone getTimeZone() {
  705. if (timezone == null) {
  706. return currentCalendar.getTimeZone();
  707. }
  708. return timezone;
  709. }
  710. /**
  711. * Set time zone that this component will use. Null value sets the default
  712. * time zone.
  713. *
  714. * @param zone
  715. * Time zone to use
  716. */
  717. public void setTimeZone(TimeZone zone) {
  718. timezone = zone;
  719. if (!currentCalendar.getTimeZone().equals(zone)) {
  720. if (zone == null) {
  721. zone = TimeZone.getDefault();
  722. }
  723. currentCalendar.setTimeZone(zone);
  724. df_date_time.setTimeZone(zone);
  725. markAsDirty();
  726. }
  727. }
  728. /**
  729. * Get the internally used Calendar instance. This is the currently used
  730. * instance of {@link java.util.Calendar} but is bound to change during the
  731. * lifetime of the component.
  732. *
  733. * @return the currently used java calendar
  734. */
  735. public java.util.Calendar getInternalCalendar() {
  736. return currentCalendar;
  737. }
  738. /**
  739. * <p>
  740. * This method restricts the weekdays that are shown. This affects both the
  741. * monthly and the weekly view. The general contract is that <b>firstDay <
  742. * lastDay</b>.
  743. * </p>
  744. *
  745. * <p>
  746. * Note that this only affects the rendering process. Events are still
  747. * requested by the dates set by {@link #setStartDate(Date)} and
  748. * {@link #setEndDate(Date)}.
  749. * </p>
  750. *
  751. * @param firstDay
  752. * the first day of the week to show, between 1 and 7
  753. */
  754. public void setFirstVisibleDayOfWeek(int firstDay) {
  755. if (this.firstDay != firstDay && firstDay >= 1 && firstDay <= 7
  756. && getLastVisibleDayOfWeek() >= firstDay) {
  757. this.firstDay = firstDay;
  758. getState().firstVisibleDayOfWeek = firstDay;
  759. }
  760. }
  761. /**
  762. * Get the first visible day of the week. Returns the weekdays as integers
  763. * represented by {@link java.util.Calendar#DAY_OF_WEEK}
  764. *
  765. * @return An integer representing the week day according to
  766. * {@link java.util.Calendar#DAY_OF_WEEK}
  767. */
  768. public int getFirstVisibleDayOfWeek() {
  769. return firstDay;
  770. }
  771. /**
  772. * <p>
  773. * This method restricts the weekdays that are shown. This affects both the
  774. * monthly and the weekly view. The general contract is that <b>firstDay <
  775. * lastDay</b>.
  776. * </p>
  777. *
  778. * <p>
  779. * Note that this only affects the rendering process. Events are still
  780. * requested by the dates set by {@link #setStartDate(Date)} and
  781. * {@link #setEndDate(Date)}.
  782. * </p>
  783. *
  784. * @param lastDay
  785. * the first day of the week to show, between 1 and 7
  786. */
  787. public void setLastVisibleDayOfWeek(int lastDay) {
  788. if (this.lastDay != lastDay && lastDay >= 1 && lastDay <= 7
  789. && getFirstVisibleDayOfWeek() <= lastDay) {
  790. this.lastDay = lastDay;
  791. getState().lastVisibleDayOfWeek = lastDay;
  792. }
  793. }
  794. /**
  795. * Get the last visible day of the week. Returns the weekdays as integers
  796. * represented by {@link java.util.Calendar#DAY_OF_WEEK}
  797. *
  798. * @return An integer representing the week day according to
  799. * {@link java.util.Calendar#DAY_OF_WEEK}
  800. */
  801. public int getLastVisibleDayOfWeek() {
  802. return lastDay;
  803. }
  804. /**
  805. * <p>
  806. * This method restricts the hours that are shown per day. This affects the
  807. * weekly view. The general contract is that <b>firstHour < lastHour</b>.
  808. * </p>
  809. *
  810. * <p>
  811. * Note that this only affects the rendering process. Events are still
  812. * requested by the dates set by {@link #setStartDate(Date)} and
  813. * {@link #setEndDate(Date)}.
  814. * </p>
  815. * You can use {@link #autoScaleVisibleHoursOfDay()} for automatic scaling
  816. * of the visible hours based on current events.
  817. *
  818. * @param firstHour
  819. * the first hour of the day to show, between 0 and 23
  820. * @see #autoScaleVisibleHoursOfDay()
  821. */
  822. public void setFirstVisibleHourOfDay(int firstHour) {
  823. if (this.firstHour != firstHour && firstHour >= 0 && firstHour <= 23
  824. && firstHour <= getLastVisibleHourOfDay()) {
  825. this.firstHour = firstHour;
  826. getState().firstHourOfDay = firstHour;
  827. }
  828. }
  829. /**
  830. * Returns the first visible hour in the week view. Returns the hour using a
  831. * 24h time format
  832. *
  833. */
  834. public int getFirstVisibleHourOfDay() {
  835. return firstHour;
  836. }
  837. /**
  838. * <p>
  839. * This method restricts the hours that are shown per day. This affects the
  840. * weekly view. The general contract is that <b>firstHour < lastHour</b>.
  841. * </p>
  842. *
  843. * <p>
  844. * Note that this only affects the rendering process. Events are still
  845. * requested by the dates set by {@link #setStartDate(Date)} and
  846. * {@link #setEndDate(Date)}.
  847. * </p>
  848. * You can use {@link #autoScaleVisibleHoursOfDay()} for automatic scaling
  849. * of the visible hours based on current events.
  850. *
  851. * @param lastHour
  852. * the first hour of the day to show, between 0 and 23
  853. * @see #autoScaleVisibleHoursOfDay()
  854. */
  855. public void setLastVisibleHourOfDay(int lastHour) {
  856. if (this.lastHour != lastHour && lastHour >= 0 && lastHour <= 23
  857. && lastHour >= getFirstVisibleHourOfDay()) {
  858. this.lastHour = lastHour;
  859. getState().lastHourOfDay = lastHour;
  860. }
  861. }
  862. /**
  863. * Returns the last visible hour in the week view. Returns the hour using a
  864. * 24h time format
  865. *
  866. */
  867. public int getLastVisibleHourOfDay() {
  868. return lastHour;
  869. }
  870. /**
  871. * Gets the date caption format for the weekly view.
  872. *
  873. * @return The pattern used in caption of dates in weekly view.
  874. */
  875. public String getWeeklyCaptionFormat() {
  876. return weeklyCaptionFormat;
  877. }
  878. /**
  879. * Sets custom date format for the weekly view. This is the caption of the
  880. * date. Format could be like "mmm MM/dd".
  881. *
  882. * @param dateFormatPattern
  883. * The date caption pattern.
  884. */
  885. public void setWeeklyCaptionFormat(String dateFormatPattern) {
  886. if (weeklyCaptionFormat == null && dateFormatPattern != null
  887. || weeklyCaptionFormat != null
  888. && !weeklyCaptionFormat.equals(dateFormatPattern)) {
  889. weeklyCaptionFormat = dateFormatPattern;
  890. markAsDirty();
  891. }
  892. }
  893. /**
  894. * Sets sort order for events. By default sort order is
  895. * {@link EventSortOrder#DURATION_DESC}.
  896. *
  897. * @param order
  898. * sort strategy for events
  899. */
  900. public void setEventSortOrder(EventSortOrder order) {
  901. if (order == null) {
  902. getState().eventSortOrder = EventSortOrder.DURATION_DESC;
  903. } else {
  904. getState().eventSortOrder = EventSortOrder.values()[order
  905. .ordinal()];
  906. }
  907. }
  908. /**
  909. * Returns sort order for events.
  910. *
  911. * @return currently active sort strategy
  912. */
  913. public EventSortOrder getEventSortOrder() {
  914. EventSortOrder order = getState(false).eventSortOrder;
  915. if (order == null) {
  916. return EventSortOrder.DURATION_DESC;
  917. } else {
  918. return order;
  919. }
  920. }
  921. private DateFormat getWeeklyCaptionFormatter() {
  922. if (weeklyCaptionFormat != null) {
  923. return new SimpleDateFormat(weeklyCaptionFormat, getLocale());
  924. } else {
  925. return SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT,
  926. getLocale());
  927. }
  928. }
  929. /**
  930. * Get the day of week by the given calendar and its locale
  931. *
  932. * @param calendar
  933. * The calendar to use
  934. * @return
  935. */
  936. private static int getDowByLocale(java.util.Calendar calendar) {
  937. int fow = calendar.get(java.util.Calendar.DAY_OF_WEEK);
  938. // monday first
  939. if (calendar.getFirstDayOfWeek() == java.util.Calendar.MONDAY) {
  940. fow = fow == java.util.Calendar.SUNDAY ? 7 : fow - 1;
  941. }
  942. return fow;
  943. }
  944. /**
  945. * Is the user allowed to trigger events which alters the events
  946. *
  947. * @return true if the client is allowed to send changes to server
  948. * @see #isEventClickAllowed()
  949. */
  950. protected boolean isClientChangeAllowed() {
  951. return !isReadOnly();
  952. }
  953. /**
  954. * Is the user allowed to trigger click events. Returns {@code true} by
  955. * default. Subclass can override this method to disallow firing event
  956. * clicks got from the client side.
  957. *
  958. * @return true if the client is allowed to click events
  959. * @see #isClientChangeAllowed()
  960. * @deprecated As of 7.4, override {@link #fireEventClick(Integer)} instead.
  961. */
  962. @Deprecated
  963. protected boolean isEventClickAllowed() {
  964. return true;
  965. }
  966. /**
  967. * Fires an event when the user selecing moving forward/backward in the
  968. * calendar.
  969. *
  970. * @param forward
  971. * True if the calendar moved forward else backward is assumed.
  972. */
  973. protected void fireNavigationEvent(boolean forward) {
  974. if (forward) {
  975. fireEvent(new ForwardEvent(this));
  976. } else {
  977. fireEvent(new BackwardEvent(this));
  978. }
  979. }
  980. /**
  981. * Fires an event move event to all server side move listerners
  982. *
  983. * @param index
  984. * The index of the event in the events list
  985. * @param newFromDatetime
  986. * The changed from date time
  987. */
  988. protected void fireEventMove(int index, Date newFromDatetime) {
  989. MoveEvent event = new MoveEvent(this, events.get(index),
  990. newFromDatetime);
  991. if (calendarEventProvider instanceof EventMoveHandler) {
  992. // Notify event provider if it is an event move handler
  993. ((EventMoveHandler) calendarEventProvider).eventMove(event);
  994. }
  995. // Notify event move handler attached by using the
  996. // setHandler(EventMoveHandler) method
  997. fireEvent(event);
  998. }
  999. /**
  1000. * Fires event when a week was clicked in the calendar.
  1001. *
  1002. * @param week
  1003. * The week that was clicked
  1004. * @param year
  1005. * The year of the week
  1006. */
  1007. protected void fireWeekClick(int week, int year) {
  1008. fireEvent(new WeekClick(this, week, year));
  1009. }
  1010. /**
  1011. * Fires event when a date was clicked in the calendar. Uses an existing
  1012. * event from the event cache.
  1013. *
  1014. * @param index
  1015. * The index of the event in the event cache.
  1016. */
  1017. protected void fireEventClick(Integer index) {
  1018. fireEvent(new EventClick(this, events.get(index)));
  1019. }
  1020. /**
  1021. * Fires event when a date was clicked in the calendar. Creates a new event
  1022. * for the date and passes it to the listener.
  1023. *
  1024. * @param date
  1025. * The date and time that was clicked
  1026. */
  1027. protected void fireDateClick(Date date) {
  1028. fireEvent(new DateClickEvent(this, date));
  1029. }
  1030. /**
  1031. * Fires an event range selected event. The event is fired when a user
  1032. * highlights an area in the calendar. The highlighted areas start and end
  1033. * dates are returned as arguments.
  1034. *
  1035. * @param from
  1036. * The start date and time of the highlighted area
  1037. * @param to
  1038. * The end date and time of the highlighted area
  1039. * @param monthlyMode
  1040. * Is the calendar in monthly mode
  1041. */
  1042. protected void fireRangeSelect(Date from, Date to, boolean monthlyMode) {
  1043. fireEvent(new RangeSelectEvent(this, from, to, monthlyMode));
  1044. }
  1045. /**
  1046. * Fires an event resize event. The event is fired when a user resizes the
  1047. * event in the calendar causing the time range of the event to increase or
  1048. * decrease. The new start and end times are returned as arguments to this
  1049. * method.
  1050. *
  1051. * @param index
  1052. * The index of the event in the event cache
  1053. * @param startTime
  1054. * The new start date and time of the event
  1055. * @param endTime
  1056. * The new end date and time of the event
  1057. */
  1058. protected void fireEventResize(int index, Date startTime, Date endTime) {
  1059. EventResize event = new EventResize(this, events.get(index), startTime,
  1060. endTime);
  1061. if (calendarEventProvider instanceof EventResizeHandler) {
  1062. // Notify event provider if it is an event resize handler
  1063. ((EventResizeHandler) calendarEventProvider).eventResize(event);
  1064. }
  1065. // Notify event resize handler attached by using the
  1066. // setHandler(EventMoveHandler) method
  1067. fireEvent(event);
  1068. }
  1069. /**
  1070. * Localized display names for week days starting from sunday. Returned
  1071. * array's length is always 7.
  1072. *
  1073. * @return Array of localized weekday names.
  1074. */
  1075. protected String[] getDayNamesShort() {
  1076. DateFormatSymbols s = new DateFormatSymbols(getLocale());
  1077. return Arrays.copyOfRange(s.getWeekdays(), 1, 8);
  1078. }
  1079. /**
  1080. * Localized display names for months starting from January. Returned
  1081. * array's length is always 12.
  1082. *
  1083. * @return Array of localized month names.
  1084. */
  1085. protected String[] getMonthNamesShort() {
  1086. DateFormatSymbols s = new DateFormatSymbols(getLocale());
  1087. return Arrays.copyOf(s.getShortMonths(), 12);
  1088. }
  1089. /**
  1090. * Gets a date that is first day in the week that target given date belongs
  1091. * to.
  1092. *
  1093. * @param date
  1094. * Target date
  1095. * @return Date that is first date in same week that given date is.
  1096. */
  1097. protected Date getFirstDateForWeek(Date date) {
  1098. int firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
  1099. currentCalendar.setTime(date);
  1100. while (firstDayOfWeek != currentCalendar
  1101. .get(java.util.Calendar.DAY_OF_WEEK)) {
  1102. currentCalendar.add(java.util.Calendar.DATE, -1);
  1103. }
  1104. return currentCalendar.getTime();
  1105. }
  1106. /**
  1107. * Gets a date that is last day in the week that target given date belongs
  1108. * to.
  1109. *
  1110. * @param date
  1111. * Target date
  1112. * @return Date that is last date in same week that given date is.
  1113. */
  1114. protected Date getLastDateForWeek(Date date) {
  1115. currentCalendar.setTime(date);
  1116. currentCalendar.add(java.util.Calendar.DATE, 1);
  1117. int firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
  1118. // Roll to weeks last day using firstdayofweek. Roll until FDofW is
  1119. // found and then roll back one day.
  1120. while (firstDayOfWeek != currentCalendar
  1121. .get(java.util.Calendar.DAY_OF_WEEK)) {
  1122. currentCalendar.add(java.util.Calendar.DATE, 1);
  1123. }
  1124. currentCalendar.add(java.util.Calendar.DATE, -1);
  1125. return currentCalendar.getTime();
  1126. }
  1127. /**
  1128. * Calculates the end time of the day using the given calendar and date
  1129. *
  1130. * @param date
  1131. * @param calendar
  1132. * the calendar instance to be used in the calculation. The given
  1133. * instance is unchanged in this operation.
  1134. * @return the given date, with time set to the end of the day
  1135. */
  1136. private static Date getEndOfDay(java.util.Calendar calendar, Date date) {
  1137. java.util.Calendar calendarClone = (java.util.Calendar) calendar
  1138. .clone();
  1139. calendarClone.setTime(date);
  1140. calendarClone.set(java.util.Calendar.MILLISECOND,
  1141. calendarClone.getActualMaximum(java.util.Calendar.MILLISECOND));
  1142. calendarClone.set(java.util.Calendar.SECOND,
  1143. calendarClone.getActualMaximum(java.util.Calendar.SECOND));
  1144. calendarClone.set(java.util.Calendar.MINUTE,
  1145. calendarClone.getActualMaximum(java.util.Calendar.MINUTE));
  1146. calendarClone.set(java.util.Calendar.HOUR,
  1147. calendarClone.getActualMaximum(java.util.Calendar.HOUR));
  1148. calendarClone.set(java.util.Calendar.HOUR_OF_DAY,
  1149. calendarClone.getActualMaximum(java.util.Calendar.HOUR_OF_DAY));
  1150. return calendarClone.getTime();
  1151. }
  1152. /**
  1153. * Calculates the end time of the day using the given calendar and date
  1154. *
  1155. * @param date
  1156. * @param calendar
  1157. * the calendar instance to be used in the calculation. The given
  1158. * instance is unchanged in this operation.
  1159. * @return the given date, with time set to the end of the day
  1160. */
  1161. private static Date getStartOfDay(java.util.Calendar calendar, Date date) {
  1162. java.util.Calendar calendarClone = (java.util.Calendar) calendar
  1163. .clone();
  1164. calendarClone.setTime(date);
  1165. calendarClone.set(java.util.Calendar.MILLISECOND, 0);
  1166. calendarClone.set(java.util.Calendar.SECOND, 0);
  1167. calendarClone.set(java.util.Calendar.MINUTE, 0);
  1168. calendarClone.set(java.util.Calendar.HOUR, 0);
  1169. calendarClone.set(java.util.Calendar.HOUR_OF_DAY, 0);
  1170. return calendarClone.getTime();
  1171. }
  1172. /**
  1173. * Finds the first day of the week and returns a day representing the start
  1174. * of that day
  1175. *
  1176. * @param start
  1177. * The actual date
  1178. * @param expandToFullWeek
  1179. * Should the returned date be moved to the start of the week
  1180. * @return If expandToFullWeek is set then it returns the first day of the
  1181. * week, else it returns a clone of the actual date with the time
  1182. * set to the start of the day
  1183. */
  1184. protected Date expandStartDate(Date start, boolean expandToFullWeek) {
  1185. // If the duration is more than week, use monthly view and get startweek
  1186. // and endweek. Example if views daterange is from tuesday to next weeks
  1187. // wednesday->expand to monday to nextweeks sunday. If firstdayofweek =
  1188. // monday
  1189. if (expandToFullWeek) {
  1190. start = getFirstDateForWeek(start);
  1191. } else {
  1192. start = (Date) start.clone();
  1193. }
  1194. // Always expand to the start of the first day to the end of the last
  1195. // day
  1196. start = getStartOfDay(currentCalendar, start);
  1197. return start;
  1198. }
  1199. /**
  1200. * Finds the last day of the week and returns a day representing the end of
  1201. * that day
  1202. *
  1203. * @param end
  1204. * The actual date
  1205. * @param expandToFullWeek
  1206. * Should the returned date be moved to the end of the week
  1207. * @return If expandToFullWeek is set then it returns the last day of the
  1208. * week, else it returns a clone of the actual date with the time
  1209. * set to the end of the day
  1210. */
  1211. protected Date expandEndDate(Date end, boolean expandToFullWeek) {
  1212. // If the duration is more than week, use monthly view and get startweek
  1213. // and endweek. Example if views daterange is from tuesday to next weeks
  1214. // wednesday->expand to monday to nextweeks sunday. If firstdayofweek =
  1215. // monday
  1216. if (expandToFullWeek) {
  1217. end = getLastDateForWeek(end);
  1218. } else {
  1219. end = (Date) end.clone();
  1220. }
  1221. // Always expand to the start of the first day to the end of the last
  1222. // day
  1223. end = getEndOfDay(currentCalendar, end);
  1224. return end;
  1225. }
  1226. /**
  1227. * Set the {@link com.vaadin.addon.calendar.event.CalendarEventProvider
  1228. * CalendarEventProvider} to be used with this calendar. The EventProvider
  1229. * is used to query for events to show, and must be non-null. By default a
  1230. * {@link com.vaadin.addon.calendar.event.BasicEventProvider
  1231. * BasicEventProvider} is used.
  1232. *
  1233. * @param calendarEventProvider
  1234. * the calendarEventProvider to set. Cannot be null.
  1235. */
  1236. public void setEventProvider(CalendarEventProvider calendarEventProvider) {
  1237. if (calendarEventProvider == null) {
  1238. throw new IllegalArgumentException(
  1239. "Calendar event provider cannot be null");
  1240. }
  1241. // remove old listener
  1242. if (getEventProvider() instanceof EventSetChangeNotifier) {
  1243. ((EventSetChangeNotifier) getEventProvider())
  1244. .removeEventSetChangeListener(this);
  1245. }
  1246. this.calendarEventProvider = calendarEventProvider;
  1247. // add new listener
  1248. if (calendarEventProvider instanceof EventSetChangeNotifier) {
  1249. ((EventSetChangeNotifier) calendarEventProvider)
  1250. .addEventSetChangeListener(this);
  1251. }
  1252. }
  1253. /**
  1254. * @return the {@link com.vaadin.addon.calendar.event.CalendarEventProvider
  1255. * CalendarEventProvider} currently used
  1256. */
  1257. public CalendarEventProvider getEventProvider() {
  1258. return calendarEventProvider;
  1259. }
  1260. /*
  1261. * (non-Javadoc)
  1262. *
  1263. * @see com.vaadin.addon.calendar.ui.CalendarEvents.EventChangeListener#
  1264. * eventChange (com.vaadin.addon.calendar.ui.CalendarEvents.EventChange)
  1265. */
  1266. @Override
  1267. public void eventSetChange(EventSetChangeEvent changeEvent) {
  1268. // sanity check
  1269. if (calendarEventProvider == changeEvent.getProvider()) {
  1270. markAsDirty();
  1271. }
  1272. }
  1273. /**
  1274. * Set the handler for the given type information. Mirrors
  1275. * {@link #addListener(String, Class, Object, Method) addListener} from
  1276. * AbstractComponent
  1277. *
  1278. * @param eventId
  1279. * A unique id for the event. Usually one of
  1280. * {@link CalendarEventId}
  1281. * @param eventType
  1282. * The class of the event, most likely a subclass of
  1283. * {@link CalendarComponentEvent}
  1284. * @param listener
  1285. * A listener that listens to the given event
  1286. * @param listenerMethod
  1287. * The method on the lister to call when the event is triggered
  1288. */
  1289. protected void setHandler(String eventId, Class<?> eventType,
  1290. EventListener listener, Method listenerMethod) {
  1291. if (handlers.get(eventId) != null) {
  1292. removeListener(eventId, eventType, handlers.get(eventId));
  1293. handlers.remove(eventId);
  1294. }
  1295. if (listener != null) {
  1296. addListener(eventId, eventType, listener, listenerMethod);
  1297. handlers.put(eventId, listener);
  1298. }
  1299. }
  1300. /*
  1301. * (non-Javadoc)
  1302. *
  1303. * @see
  1304. * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
  1305. * #addListener
  1306. * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.ForwardHandler)
  1307. */
  1308. @Override
  1309. public void setHandler(ForwardHandler listener) {
  1310. setHandler(ForwardEvent.EVENT_ID, ForwardEvent.class, listener,
  1311. ForwardHandler.forwardMethod);
  1312. }
  1313. /*
  1314. * (non-Javadoc)
  1315. *
  1316. * @see
  1317. * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
  1318. * #addListener
  1319. * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.BackwardHandler)
  1320. */
  1321. @Override
  1322. public void setHandler(BackwardHandler listener) {
  1323. setHandler(BackwardEvent.EVENT_ID, BackwardEvent.class, listener,
  1324. BackwardHandler.backwardMethod);
  1325. }
  1326. /*
  1327. * (non-Javadoc)
  1328. *
  1329. * @see
  1330. * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
  1331. * #addListener
  1332. * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.DateClickHandler)
  1333. */
  1334. @Override
  1335. public void setHandler(DateClickHandler listener) {
  1336. setHandler(DateClickEvent.EVENT_ID, DateClickEvent.class, listener,
  1337. DateClickHandler.dateClickMethod);
  1338. }
  1339. /*
  1340. * (non-Javadoc)
  1341. *
  1342. * @see
  1343. * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
  1344. * #addListener
  1345. * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventClickHandler)
  1346. */
  1347. @Override
  1348. public void setHandler(EventClickHandler listener) {
  1349. setHandler(EventClick.EVENT_ID, EventClick.class, listener,
  1350. EventClickHandler.eventClickMethod);
  1351. }
  1352. /*
  1353. * (non-Javadoc)
  1354. *
  1355. * @see
  1356. * com.vaadin.addon.calendar.ui.CalendarComponentEvents.NavigationNotifier
  1357. * #addListener
  1358. * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.WeekClickHandler)
  1359. */
  1360. @Override
  1361. public void setHandler(WeekClickHandler listener) {
  1362. setHandler(WeekClick.EVENT_ID, WeekClick.class, listener,
  1363. WeekClickHandler.weekClickMethod);
  1364. }
  1365. /*
  1366. * (non-Javadoc)
  1367. *
  1368. * @see
  1369. * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeNotifier
  1370. * #addListener
  1371. * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventResizeHandler
  1372. * )
  1373. */
  1374. @Override
  1375. public void setHandler(EventResizeHandler listener) {
  1376. setHandler(EventResize.EVENT_ID, EventResize.class, listener,
  1377. EventResizeHandler.eventResizeMethod);
  1378. }
  1379. /*
  1380. * (non-Javadoc)
  1381. *
  1382. * @see
  1383. * com.vaadin.addon.calendar.ui.CalendarComponentEvents.RangeSelectNotifier
  1384. * #addListener
  1385. * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.RangeSelectHandler
  1386. * )
  1387. */
  1388. @Override
  1389. public void setHandler(RangeSelectHandler listener) {
  1390. setHandler(RangeSelectEvent.EVENT_ID, RangeSelectEvent.class, listener,
  1391. RangeSelectHandler.rangeSelectMethod);
  1392. }
  1393. /*
  1394. * (non-Javadoc)
  1395. *
  1396. * @see
  1397. * com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveNotifier
  1398. * #addListener
  1399. * (com.vaadin.addon.calendar.ui.CalendarComponentEvents.EventMoveHandler)
  1400. */
  1401. @Override
  1402. public void setHandler(EventMoveHandler listener) {
  1403. setHandler(MoveEvent.EVENT_ID, MoveEvent.class, listener,
  1404. EventMoveHandler.eventMoveMethod);
  1405. }
  1406. /*
  1407. * (non-Javadoc)
  1408. *
  1409. * @see com.vaadin.addon.calendar.ui.CalendarComponentEvents.
  1410. * CalendarEventNotifier #getHandler(java.lang.String)
  1411. */
  1412. @Override
  1413. public EventListener getHandler(String eventId) {
  1414. return handlers.get(eventId);
  1415. }
  1416. /**
  1417. * Get the currently active drop handler
  1418. */
  1419. @Override
  1420. public DropHandler getDropHandler() {
  1421. return dropHandler;
  1422. }
  1423. /**
  1424. * Set the drop handler for the calendar See {@link DropHandler} for
  1425. * implementation details.
  1426. *
  1427. * @param dropHandler
  1428. * The drop handler to set
  1429. */
  1430. public void setDropHandler(DropHandler dropHandler) {
  1431. this.dropHandler = dropHandler;
  1432. }
  1433. /*
  1434. * (non-Javadoc)
  1435. *
  1436. * @see
  1437. * com.vaadin.event.dd.DropTarget#translateDropTargetDetails(java.util.Map)
  1438. */
  1439. @Override
  1440. public TargetDetails translateDropTargetDetails(
  1441. Map<String, Object> clientVariables) {
  1442. Map<String, Object> serverVariables = new HashMap<>();
  1443. if (clientVariables.containsKey("dropSlotIndex")) {
  1444. int slotIndex = (Integer) clientVariables.get("dropSlotIndex");
  1445. int dayIndex = (Integer) clientVariables.get("dropDayIndex");
  1446. currentCalendar.setTime(getStartOfDay(currentCalendar, startDate));
  1447. currentCalendar.add(java.util.Calendar.DATE, dayIndex);
  1448. // change this if slot length is modified
  1449. currentCalendar.add(java.util.Calendar.MINUTE, slotIndex * 30);
  1450. serverVariables.put("dropTime", currentCalendar.getTime());
  1451. } else {
  1452. int dayIndex = (Integer) clientVariables.get("dropDayIndex");
  1453. currentCalendar.setTime(expandStartDate(startDate, true));
  1454. currentCalendar.add(java.util.Calendar.DATE, dayIndex);
  1455. serverVariables.put("dropDay", currentCalendar.getTime());
  1456. }
  1457. serverVariables.put("mouseEvent", clientVariables.get("mouseEvent"));
  1458. CalendarTargetDetails td = new CalendarTargetDetails(serverVariables,
  1459. this);
  1460. td.setHasDropTime(clientVariables.containsKey("dropSlotIndex"));
  1461. return td;
  1462. }
  1463. /**
  1464. * Sets a container as a data source for the events in the calendar.
  1465. * Equivalent for doing
  1466. * <code>Calendar.setEventProvider(new ContainerEventProvider(container))</code>
  1467. *
  1468. * Use this method if you are adding a container which uses the default
  1469. * property ids like {@link BeanItemContainer} for instance. If you are
  1470. * using custom properties instead use
  1471. * {@link Calendar#setContainerDataSource(com.vaadin.v7.data.Container.Indexed, Object, Object, Object, Object, Object)}
  1472. *
  1473. * Please note that the container must be sorted by date!
  1474. *
  1475. * @param container
  1476. * The container to use as a datasource
  1477. */
  1478. public void setContainerDataSource(Container.Indexed container) {
  1479. ContainerEventProvider provider = new ContainerEventProvider(container);
  1480. provider.addEventSetChangeListener(
  1481. new CalendarEventProvider.EventSetChangeListener() {
  1482. @Override
  1483. public void eventSetChange(
  1484. EventSetChangeEvent changeEvent) {
  1485. // Repaint if events change
  1486. markAsDirty();
  1487. }
  1488. });
  1489. provider.addEventChangeListener(new EventChangeListener() {
  1490. @Override
  1491. public void eventChange(EventChangeEvent changeEvent) {
  1492. // Repaint if event changes
  1493. markAsDirty();
  1494. }
  1495. });
  1496. setEventProvider(provider);
  1497. }
  1498. /**
  1499. * Sets a container as a data source for the events in the calendar.
  1500. * Equivalent for doing
  1501. * <code>Calendar.setEventProvider(new ContainerEventProvider(container))</code>
  1502. *
  1503. * Please note that the container must be sorted by date!
  1504. *
  1505. * @param container
  1506. * The container to use as a data source
  1507. * @param captionProperty
  1508. * The property that has the caption, null if no caption property
  1509. * is present
  1510. * @param descriptionProperty
  1511. * The property that has the description, null if no description
  1512. * property is present
  1513. * @param startDateProperty
  1514. * The property that has the starting date
  1515. * @param endDateProperty
  1516. * The property that has the ending date
  1517. * @param styleNameProperty
  1518. * The property that has the stylename, null if no stylname
  1519. * property is present
  1520. */
  1521. public void setContainerDataSource(Container.Indexed container,
  1522. Object captionProperty, Object descriptionProperty,
  1523. Object startDateProperty, Object endDateProperty,
  1524. Object styleNameProperty) {
  1525. ContainerEventProvider provider = new ContainerEventProvider(container);
  1526. provider.setCaptionProperty(captionProperty);
  1527. provider.setDescriptionProperty(descriptionProperty);
  1528. provider.setStartDateProperty(startDateProperty);
  1529. provider.setEndDateProperty(endDateProperty);
  1530. provider.setStyleNameProperty(styleNameProperty);
  1531. provider.addEventSetChangeListener(
  1532. new CalendarEventProvider.EventSetChangeListener() {
  1533. @Override
  1534. public void eventSetChange(
  1535. EventSetChangeEvent changeEvent) {
  1536. // Repaint if events change
  1537. markAsDirty();
  1538. }
  1539. });
  1540. provider.addEventChangeListener(new EventChangeListener() {
  1541. @Override
  1542. public void eventChange(EventChangeEvent changeEvent) {
  1543. // Repaint if event changes
  1544. markAsDirty();
  1545. }
  1546. });
  1547. setEventProvider(provider);
  1548. }
  1549. /*
  1550. * (non-Javadoc)
  1551. *
  1552. * @see
  1553. * com.vaadin.addon.calendar.event.CalendarEventProvider#getEvents(java.
  1554. * util.Date, java.util.Date)
  1555. */
  1556. @Override
  1557. public List<CalendarEvent> getEvents(Date startDate, Date endDate) {
  1558. List<CalendarEvent> events = getEventProvider().getEvents(startDate,
  1559. endDate);
  1560. cacheMinMaxTimeOfDay(events);
  1561. return events;
  1562. }
  1563. /*
  1564. * (non-Javadoc)
  1565. *
  1566. * @see
  1567. * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#addEvent
  1568. * (com.vaadin.addon.calendar.event.CalendarEvent)
  1569. */
  1570. @Override
  1571. public void addEvent(CalendarEvent event) {
  1572. if (getEventProvider() instanceof CalendarEditableEventProvider) {
  1573. CalendarEditableEventProvider provider = (CalendarEditableEventProvider) getEventProvider();
  1574. provider.addEvent(event);
  1575. markAsDirty();
  1576. } else {
  1577. throw new UnsupportedOperationException(
  1578. "Event provider does not support adding events");
  1579. }
  1580. }
  1581. /*
  1582. * (non-Javadoc)
  1583. *
  1584. * @see
  1585. * com.vaadin.addon.calendar.event.CalendarEditableEventProvider#removeEvent
  1586. * (com.vaadin.addon.calendar.event.CalendarEvent)
  1587. */
  1588. @Override
  1589. public void removeEvent(CalendarEvent event) {
  1590. if (getEventProvider() instanceof CalendarEditableEventProvider) {
  1591. CalendarEditableEventProvider provider = (CalendarEditableEventProvider) getEventProvider();
  1592. provider.removeEvent(event);
  1593. markAsDirty();
  1594. } else {
  1595. throw new UnsupportedOperationException(
  1596. "Event provider does not support removing events");
  1597. }
  1598. }
  1599. /**
  1600. * Adds an action handler to the calender that handles event produced by the
  1601. * context menu.
  1602. *
  1603. * <p>
  1604. * The {@link Handler#getActions(Object, Object)} parameters depend on what
  1605. * view the Calendar is in:
  1606. * <ul>
  1607. * <li>If the Calendar is in <i>Day or Week View</i> then the target
  1608. * parameter will be a {@link CalendarDateRange} with a range of
  1609. * half-an-hour. The {@link Handler#getActions(Object, Object)} method will
  1610. * be called once per half-hour slot.</li>
  1611. * <li>If the Calendar is in <i>Month View</i> then the target parameter
  1612. * will be a {@link CalendarDateRange} with a range of one day. The
  1613. * {@link Handler#getActions(Object, Object)} will be called once for each
  1614. * day.
  1615. * </ul>
  1616. * The Dates passed into the {@link CalendarDateRange} are in the same
  1617. * timezone as the calendar is.
  1618. * </p>
  1619. *
  1620. * <p>
  1621. * The {@link Handler#handleAction(Action, Object, Object)} parameters
  1622. * depend on what the context menu is called upon:
  1623. * <ul>
  1624. * <li>If the context menu is called upon an event then the target parameter
  1625. * is the event, i.e. instanceof {@link CalendarEvent}</li>
  1626. * <li>If the context menu is called upon an empty slot then the target is a
  1627. * {@link Date} representing that slot
  1628. * </ul>
  1629. * </p>
  1630. */
  1631. @Override
  1632. public void addActionHandler(Handler actionHandler) {
  1633. if (actionHandler != null) {
  1634. if (actionHandlers == null) {
  1635. actionHandlers = new LinkedList<>();
  1636. actionMapper = new KeyMapper<>();
  1637. }
  1638. if (!actionHandlers.contains(actionHandler)) {
  1639. actionHandlers.add(actionHandler);
  1640. markAsDirty();
  1641. }
  1642. }
  1643. }
  1644. /**
  1645. * Is the calendar in a mode where all days of the month is shown
  1646. *
  1647. * @return Returns true if calendar is in monthly mode and false if it is in
  1648. * weekly mode
  1649. */
  1650. public boolean isMonthlyMode() {
  1651. CalendarState state = getState(false);
  1652. if (state.days != null) {
  1653. return state.days.size() > 7;
  1654. } else {
  1655. // Default mode
  1656. return true;
  1657. }
  1658. }
  1659. /*
  1660. * (non-Javadoc)
  1661. *
  1662. * @see
  1663. * com.vaadin.event.Action.Container#removeActionHandler(com.vaadin.event
  1664. * .Action.Handler)
  1665. */
  1666. @Override
  1667. public void removeActionHandler(Handler actionHandler) {
  1668. if (actionHandlers != null && actionHandlers.contains(actionHandler)) {
  1669. actionHandlers.remove(actionHandler);
  1670. if (actionHandlers.isEmpty()) {
  1671. actionHandlers = null;
  1672. actionMapper = null;
  1673. }
  1674. markAsDirty();
  1675. }
  1676. }
  1677. private class CalendarServerRpcImpl implements CalendarServerRpc {
  1678. @Override
  1679. public void eventMove(int eventIndex, String newDate) {
  1680. if (!isClientChangeAllowed()) {
  1681. return;
  1682. }
  1683. if (newDate != null) {
  1684. try {
  1685. Date d = df_date_time.parse(newDate);
  1686. if (eventIndex >= 0 && eventIndex < events.size()
  1687. && events.get(eventIndex) != null) {
  1688. fireEventMove(eventIndex, d);
  1689. }
  1690. } catch (ParseException e) {
  1691. getLogger().log(Level.WARNING, e.getMessage());
  1692. }
  1693. }
  1694. }
  1695. @Override
  1696. public void rangeSelect(String range) {
  1697. if (!isClientChangeAllowed()) {
  1698. return;
  1699. }
  1700. if (range != null && range.length() > 14 && range.contains("TO")) {
  1701. String[] dates = range.split("TO");
  1702. try {
  1703. Date d1 = df_date.parse(dates[0]);
  1704. Date d2 = df_date.parse(dates[1]);
  1705. fireRangeSelect(d1, d2, true);
  1706. } catch (ParseException e) {
  1707. // NOP
  1708. }
  1709. } else if (range != null && range.length() > 12
  1710. && range.contains(":")) {
  1711. String[] dates = range.split(":");
  1712. if (dates.length == 3) {
  1713. try {
  1714. Date d = df_date.parse(dates[0]);
  1715. currentCalendar.setTime(d);
  1716. int startMinutes = Integer.parseInt(dates[1]);
  1717. int endMinutes = Integer.parseInt(dates[2]);
  1718. currentCalendar.add(java.util.Calendar.MINUTE,
  1719. startMinutes);
  1720. Date start = currentCalendar.getTime();
  1721. currentCalendar.add(java.util.Calendar.MINUTE,
  1722. endMinutes - startMinutes);
  1723. Date end = currentCalendar.getTime();
  1724. fireRangeSelect(start, end, false);
  1725. } catch (ParseException e) {
  1726. // NOP
  1727. } catch (NumberFormatException e) {
  1728. // NOP
  1729. }
  1730. }
  1731. }
  1732. }
  1733. @Override
  1734. public void forward() {
  1735. fireEvent(new ForwardEvent(Calendar.this));
  1736. }
  1737. @Override
  1738. public void backward() {
  1739. fireEvent(new BackwardEvent(Calendar.this));
  1740. }
  1741. @Override
  1742. public void dateClick(String date) {
  1743. if (date != null && date.length() > 6) {
  1744. try {
  1745. Date d = df_date.parse(date);
  1746. fireDateClick(d);
  1747. } catch (ParseException e) {
  1748. }
  1749. }
  1750. }
  1751. @Override
  1752. public void weekClick(String event) {
  1753. if (event.length() > 0 && event.contains("w")) {
  1754. String[] splitted = event.split("w");
  1755. if (splitted.length == 2) {
  1756. try {
  1757. int yr = Integer.parseInt(splitted[0]);
  1758. int week = Integer.parseInt(splitted[1]);
  1759. fireWeekClick(week, yr);
  1760. } catch (NumberFormatException e) {
  1761. // NOP
  1762. }
  1763. }
  1764. }
  1765. }
  1766. @Override
  1767. public void eventClick(int eventIndex) {
  1768. if (!isEventClickAllowed()) {
  1769. return;
  1770. }
  1771. if (eventIndex >= 0 && eventIndex < events.size()
  1772. && events.get(eventIndex) != null) {
  1773. fireEventClick(eventIndex);
  1774. }
  1775. }
  1776. @Override
  1777. public void eventResize(int eventIndex, String newStartDate,
  1778. String newEndDate) {
  1779. if (!isClientChangeAllowed()) {
  1780. return;
  1781. }
  1782. if (newStartDate != null && !"".equals(newStartDate)
  1783. && newEndDate != null && !"".equals(newEndDate)) {
  1784. try {
  1785. Date newStartTime = df_date_time.parse(newStartDate);
  1786. Date newEndTime = df_date_time.parse(newEndDate);
  1787. fireEventResize(eventIndex, newStartTime, newEndTime);
  1788. } catch (ParseException e) {
  1789. // NOOP
  1790. }
  1791. }
  1792. }
  1793. @Override
  1794. public void scroll(int scrollPosition) {
  1795. scrollTop = scrollPosition;
  1796. markAsDirty();
  1797. }
  1798. @Override
  1799. public void actionOnEmptyCell(String actionKey, String startDate,
  1800. String endDate) {
  1801. Action action = actionMapper.get(actionKey);
  1802. SimpleDateFormat formatter = new SimpleDateFormat(
  1803. DateConstants.ACTION_DATE_FORMAT_PATTERN);
  1804. formatter.setTimeZone(getTimeZone());
  1805. try {
  1806. Date start = formatter.parse(startDate);
  1807. for (Action.Handler ah : actionHandlers) {
  1808. ah.handleAction(action, Calendar.this, start);
  1809. }
  1810. } catch (ParseException e) {
  1811. getLogger().log(Level.WARNING,
  1812. "Could not parse action date string");
  1813. }
  1814. }
  1815. @Override
  1816. public void actionOnEvent(String actionKey, String startDate,
  1817. String endDate, int eventIndex) {
  1818. Action action = actionMapper.get(actionKey);
  1819. SimpleDateFormat formatter = new SimpleDateFormat(
  1820. DateConstants.ACTION_DATE_FORMAT_PATTERN);
  1821. formatter.setTimeZone(getTimeZone());
  1822. for (Action.Handler ah : actionHandlers) {
  1823. ah.handleAction(action, Calendar.this, events.get(eventIndex));
  1824. }
  1825. }
  1826. }
  1827. /*
  1828. * (non-Javadoc)
  1829. *
  1830. * @see com.vaadin.server.VariableOwner#changeVariables(java.lang.Object,
  1831. * java.util.Map)
  1832. */
  1833. @Override
  1834. public void changeVariables(Object source, Map<String, Object> variables) {
  1835. /*
  1836. * Only defined to fulfill the LegacyComponent interface used for
  1837. * calendar drag & drop. No implementation required.
  1838. */
  1839. }
  1840. /*
  1841. * (non-Javadoc)
  1842. *
  1843. * @see
  1844. * com.vaadin.ui.LegacyComponent#paintContent(com.vaadin.server.PaintTarget)
  1845. */
  1846. @Override
  1847. public void paintContent(PaintTarget target) throws PaintException {
  1848. if (dropHandler != null) {
  1849. dropHandler.getAcceptCriterion().paint(target);
  1850. }
  1851. }
  1852. /**
  1853. * Sets whether the event captions are rendered as HTML.
  1854. * <p>
  1855. * If set to true, the captions are rendered in the browser as HTML and the
  1856. * developer is responsible for ensuring no harmful HTML is used. If set to
  1857. * false, the caption is rendered in the browser as plain text.
  1858. * <p>
  1859. * The default is false, i.e. to render that caption as plain text.
  1860. *
  1861. * @param captionAsHtml
  1862. * true if the captions are rendered as HTML, false if rendered
  1863. * as plain text
  1864. */
  1865. public void setEventCaptionAsHtml(boolean eventCaptionAsHtml) {
  1866. getState().eventCaptionAsHtml = eventCaptionAsHtml;
  1867. }
  1868. /**
  1869. * Checks whether event captions are rendered as HTML
  1870. * <p>
  1871. * The default is false, i.e. to render that caption as plain text.
  1872. *
  1873. * @return true if the captions are rendered as HTML, false if rendered as
  1874. * plain text
  1875. */
  1876. public boolean isEventCaptionAsHtml() {
  1877. return getState(false).eventCaptionAsHtml;
  1878. }
  1879. @Override
  1880. public void readDesign(Element design, DesignContext designContext) {
  1881. super.readDesign(design, designContext);
  1882. Attributes attr = design.attributes();
  1883. if (design.hasAttr("time-format")) {
  1884. setTimeFormat(TimeFormat.valueOf(
  1885. "Format" + design.attr("time-format").toUpperCase()));
  1886. }
  1887. if (design.hasAttr("start-date")) {
  1888. setStartDate(DesignAttributeHandler.readAttribute("start-date",
  1889. attr, Date.class));
  1890. }
  1891. if (design.hasAttr("end-date")) {
  1892. setEndDate(DesignAttributeHandler.readAttribute("end-date", attr,
  1893. Date.class));
  1894. }
  1895. };
  1896. @Override
  1897. public void writeDesign(Element design, DesignContext designContext) {
  1898. super.writeDesign(design, designContext);
  1899. if (currentTimeFormat != null) {
  1900. design.attr("time-format",
  1901. currentTimeFormat == TimeFormat.Format12H ? "12h" : "24h");
  1902. }
  1903. if (startDate != null) {
  1904. design.attr("start-date", df_date.format(getStartDate()));
  1905. }
  1906. if (endDate != null) {
  1907. design.attr("end-date", df_date.format(getEndDate()));
  1908. }
  1909. if (!getTimeZone().equals(TimeZone.getDefault())) {
  1910. design.attr("time-zone", getTimeZone().getID());
  1911. }
  1912. }
  1913. @Override
  1914. protected Collection<String> getCustomAttributes() {
  1915. Collection<String> customAttributes = super.getCustomAttributes();
  1916. customAttributes.add("time-format");
  1917. customAttributes.add("start-date");
  1918. customAttributes.add("end-date");
  1919. return customAttributes;
  1920. }
  1921. /**
  1922. * Allow setting first day of week independent of Locale. Set to null if you
  1923. * want first day of week being defined by the locale
  1924. *
  1925. * @since 7.6
  1926. * @param dayOfWeek
  1927. * any of java.util.Calendar.SUNDAY..java.util.Calendar.SATURDAY
  1928. * or null to revert to default first day of week by locale
  1929. */
  1930. public void setFirstDayOfWeek(Integer dayOfWeek) {
  1931. int minimalSupported = java.util.Calendar.SUNDAY;
  1932. int maximalSupported = java.util.Calendar.SATURDAY;
  1933. if (dayOfWeek != null && (dayOfWeek < minimalSupported
  1934. || dayOfWeek > maximalSupported)) {
  1935. throw new IllegalArgumentException(String.format(
  1936. "Day of week must be between %s and %s. Actually received: %s",
  1937. minimalSupported, maximalSupported, dayOfWeek));
  1938. }
  1939. customFirstDayOfWeek = dayOfWeek;
  1940. markAsDirty();
  1941. }
  1942. }