Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

Calendar.java 71KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024
  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.AbstractComponent;
  50. import com.vaadin.ui.LegacyComponent;
  51. import com.vaadin.ui.declarative.DesignAttributeHandler;
  52. import com.vaadin.ui.declarative.DesignContext;
  53. import com.vaadin.v7.data.Container;
  54. import com.vaadin.v7.data.util.BeanItemContainer;
  55. import com.vaadin.v7.shared.ui.calendar.CalendarEventId;
  56. import com.vaadin.v7.shared.ui.calendar.CalendarServerRpc;
  57. import com.vaadin.v7.shared.ui.calendar.CalendarState;
  58. import com.vaadin.v7.shared.ui.calendar.CalendarState.EventSortOrder;
  59. import com.vaadin.v7.shared.ui.calendar.DateConstants;
  60. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvent;
  61. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents;
  62. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.BackwardEvent;
  63. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.BackwardHandler;
  64. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.DateClickEvent;
  65. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.DateClickHandler;
  66. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventClick;
  67. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventClickHandler;
  68. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventMoveHandler;
  69. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventResize;
  70. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.EventResizeHandler;
  71. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.ForwardEvent;
  72. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.ForwardHandler;
  73. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.MoveEvent;
  74. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.RangeSelectEvent;
  75. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.RangeSelectHandler;
  76. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.WeekClick;
  77. import com.vaadin.v7.ui.components.calendar.CalendarComponentEvents.WeekClickHandler;
  78. import com.vaadin.v7.ui.components.calendar.CalendarDateRange;
  79. import com.vaadin.v7.ui.components.calendar.CalendarTargetDetails;
  80. import com.vaadin.v7.ui.components.calendar.ContainerEventProvider;
  81. import com.vaadin.v7.ui.components.calendar.event.BasicEventProvider;
  82. import com.vaadin.v7.ui.components.calendar.event.CalendarEditableEventProvider;
  83. import com.vaadin.v7.ui.components.calendar.event.CalendarEvent;
  84. import com.vaadin.v7.ui.components.calendar.event.CalendarEvent.EventChangeEvent;
  85. import com.vaadin.v7.ui.components.calendar.event.CalendarEvent.EventChangeListener;
  86. import com.vaadin.v7.ui.components.calendar.event.CalendarEventProvider;
  87. import com.vaadin.v7.ui.components.calendar.handler.BasicBackwardHandler;
  88. import com.vaadin.v7.ui.components.calendar.handler.BasicDateClickHandler;
  89. import com.vaadin.v7.ui.components.calendar.handler.BasicEventMoveHandler;
  90. import com.vaadin.v7.ui.components.calendar.handler.BasicEventResizeHandler;
  91. import com.vaadin.v7.ui.components.calendar.handler.BasicForwardHandler;
  92. import com.vaadin.v7.ui.components.calendar.handler.BasicWeekClickHandler;
  93. /**
  94. * <p>
  95. * Vaadin Calendar is for visualizing events in a calendar. Calendar events can
  96. * be visualized in the variable length view depending on the start and end
  97. * dates.
  98. * </p>
  99. *
  100. * <li>You can set the viewable date range with the {@link #setStartDate(Date)}
  101. * and {@link #setEndDate(Date)} methods. Calendar has a default date range of
  102. * one week</li>
  103. *
  104. * <li>Calendar has two kind of views: monthly and weekly view</li>
  105. *
  106. * <li>If date range is seven days or shorter, the weekly view is used.</li>
  107. *
  108. * <li>Calendar queries its events by using a {@link CalendarEventProvider}. By
  109. * default, a {@link BasicEventProvider} is used.</li>
  110. *
  111. * @since 7.1
  112. * @author Vaadin Ltd.
  113. *
  114. * @deprecated As of 8.0, no replacement available.
  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<String, EventListener>();
  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 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<CalendarState.Event>();
  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<CalendarDateRange, Set<Action>>();
  548. List<CalendarState.Day> days = new ArrayList<CalendarState.Day>();
  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<Action>(
  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<Action>(
  634. Arrays.asList(actions));
  635. actionMap.put(range, actionSet);
  636. }
  637. }
  638. private List<CalendarState.Action> createActionsList(
  639. Map<CalendarDateRange, Set<Action>> actionMap) {
  640. if (actionMap.isEmpty()) {
  641. return null;
  642. }
  643. List<CalendarState.Action> calendarActions = new ArrayList<CalendarState.Action>();
  644. SimpleDateFormat formatter = new SimpleDateFormat(
  645. DateConstants.ACTION_DATE_FORMAT_PATTERN);
  646. formatter.setTimeZone(getTimeZone());
  647. for (Entry<CalendarDateRange, Set<Action>> entry : actionMap
  648. .entrySet()) {
  649. CalendarDateRange range = entry.getKey();
  650. Set<Action> actions = entry.getValue();
  651. for (Action action : actions) {
  652. String key = actionMapper.key(action);
  653. CalendarState.Action calendarAction = new CalendarState.Action();
  654. calendarAction.actionKey = key;
  655. calendarAction.caption = action.getCaption();
  656. setResource(key, action.getIcon());
  657. calendarAction.iconKey = key;
  658. calendarAction.startDate = formatter.format(range.getStart());
  659. calendarAction.endDate = formatter.format(range.getEnd());
  660. calendarActions.add(calendarAction);
  661. }
  662. }
  663. return calendarActions;
  664. }
  665. /**
  666. * Gets currently active time format. Value is either TimeFormat.Format12H
  667. * or TimeFormat.Format24H.
  668. *
  669. * @return TimeFormat Format for the time.
  670. */
  671. public TimeFormat getTimeFormat() {
  672. if (currentTimeFormat == null) {
  673. SimpleDateFormat f;
  674. if (getLocale() == null) {
  675. f = (SimpleDateFormat) SimpleDateFormat
  676. .getTimeInstance(SimpleDateFormat.SHORT);
  677. } else {
  678. f = (SimpleDateFormat) SimpleDateFormat
  679. .getTimeInstance(SimpleDateFormat.SHORT, getLocale());
  680. }
  681. String p = f.toPattern();
  682. if (p.indexOf("HH") != -1 || p.indexOf("H") != -1) {
  683. return TimeFormat.Format24H;
  684. }
  685. return TimeFormat.Format12H;
  686. }
  687. return currentTimeFormat;
  688. }
  689. /**
  690. * Example: <code>setTimeFormat(TimeFormat.Format12H);</code><br>
  691. * Set to null, if you want the format being defined by the locale.
  692. *
  693. * @param format
  694. * Set 12h or 24h format. Default is defined by the locale.
  695. */
  696. public void setTimeFormat(TimeFormat format) {
  697. currentTimeFormat = format;
  698. markAsDirty();
  699. }
  700. /**
  701. * Returns a time zone that is currently used by this component.
  702. *
  703. * @return Component's Time zone
  704. */
  705. public TimeZone getTimeZone() {
  706. if (timezone == null) {
  707. return currentCalendar.getTimeZone();
  708. }
  709. return timezone;
  710. }
  711. /**
  712. * Set time zone that this component will use. Null value sets the default
  713. * time zone.
  714. *
  715. * @param zone
  716. * Time zone to use
  717. */
  718. public void setTimeZone(TimeZone zone) {
  719. timezone = zone;
  720. if (!currentCalendar.getTimeZone().equals(zone)) {
  721. if (zone == null) {
  722. zone = TimeZone.getDefault();
  723. }
  724. currentCalendar.setTimeZone(zone);
  725. df_date_time.setTimeZone(zone);
  726. markAsDirty();
  727. }
  728. }
  729. /**
  730. * Get the internally used Calendar instance. This is the currently used
  731. * instance of {@link java.util.Calendar} but is bound to change during the
  732. * lifetime of the component.
  733. *
  734. * @return the currently used java calendar
  735. */
  736. public java.util.Calendar getInternalCalendar() {
  737. return currentCalendar;
  738. }
  739. /**
  740. * <p>
  741. * This method restricts the weekdays that are shown. This affects both the
  742. * monthly and the weekly view. The general contract is that <b>firstDay <
  743. * lastDay</b>.
  744. * </p>
  745. *
  746. * <p>
  747. * Note that this only affects the rendering process. Events are still
  748. * requested by the dates set by {@link #setStartDate(Date)} and
  749. * {@link #setEndDate(Date)}.
  750. * </p>
  751. *
  752. * @param firstDay
  753. * the first day of the week to show, between 1 and 7
  754. */
  755. public void setFirstVisibleDayOfWeek(int firstDay) {
  756. if (this.firstDay != firstDay && firstDay >= 1 && firstDay <= 7
  757. && getLastVisibleDayOfWeek() >= firstDay) {
  758. this.firstDay = firstDay;
  759. getState().firstVisibleDayOfWeek = firstDay;
  760. }
  761. }
  762. /**
  763. * Get the first visible day of the week. Returns the weekdays as integers
  764. * represented by {@link java.util.Calendar#DAY_OF_WEEK}
  765. *
  766. * @return An integer representing the week day according to
  767. * {@link java.util.Calendar#DAY_OF_WEEK}
  768. */
  769. public int getFirstVisibleDayOfWeek() {
  770. return firstDay;
  771. }
  772. /**
  773. * <p>
  774. * This method restricts the weekdays that are shown. This affects both the
  775. * monthly and the weekly view. The general contract is that <b>firstDay <
  776. * lastDay</b>.
  777. * </p>
  778. *
  779. * <p>
  780. * Note that this only affects the rendering process. Events are still
  781. * requested by the dates set by {@link #setStartDate(Date)} and
  782. * {@link #setEndDate(Date)}.
  783. * </p>
  784. *
  785. * @param lastDay
  786. * the first day of the week to show, between 1 and 7
  787. */
  788. public void setLastVisibleDayOfWeek(int lastDay) {
  789. if (this.lastDay != lastDay && lastDay >= 1 && lastDay <= 7
  790. && getFirstVisibleDayOfWeek() <= lastDay) {
  791. this.lastDay = lastDay;
  792. getState().lastVisibleDayOfWeek = lastDay;
  793. }
  794. }
  795. /**
  796. * Get the last visible day of the week. Returns the weekdays as integers
  797. * represented by {@link java.util.Calendar#DAY_OF_WEEK}
  798. *
  799. * @return An integer representing the week day according to
  800. * {@link java.util.Calendar#DAY_OF_WEEK}
  801. */
  802. public int getLastVisibleDayOfWeek() {
  803. return lastDay;
  804. }
  805. /**
  806. * <p>
  807. * This method restricts the hours that are shown per day. This affects the
  808. * weekly view. The general contract is that <b>firstHour < lastHour</b>.
  809. * </p>
  810. *
  811. * <p>
  812. * Note that this only affects the rendering process. Events are still
  813. * requested by the dates set by {@link #setStartDate(Date)} and
  814. * {@link #setEndDate(Date)}.
  815. * </p>
  816. * You can use {@link #autoScaleVisibleHoursOfDay()} for automatic scaling
  817. * of the visible hours based on current events.
  818. *
  819. * @param firstHour
  820. * the first hour of the day to show, between 0 and 23
  821. * @see #autoScaleVisibleHoursOfDay()
  822. */
  823. public void setFirstVisibleHourOfDay(int firstHour) {
  824. if (this.firstHour != firstHour && firstHour >= 0 && firstHour <= 23
  825. && firstHour <= getLastVisibleHourOfDay()) {
  826. this.firstHour = firstHour;
  827. getState().firstHourOfDay = firstHour;
  828. }
  829. }
  830. /**
  831. * Returns the first visible hour in the week view. Returns the hour using a
  832. * 24h time format
  833. *
  834. */
  835. public int getFirstVisibleHourOfDay() {
  836. return firstHour;
  837. }
  838. /**
  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. * Note that this only affects the rendering process. Events are still
  843. * requested by the dates set by {@link #setStartDate(Date)} and
  844. * {@link #setEndDate(Date)}.
  845. * <p>
  846. * You can use {@link #autoScaleVisibleHoursOfDay()} for automatic scaling
  847. * of the visible hours based on current events.
  848. *
  849. * @param lastHour
  850. * the first hour of the day to show, between 0 and 23
  851. * @see #autoScaleVisibleHoursOfDay()
  852. */
  853. public void setLastVisibleHourOfDay(int lastHour) {
  854. if (this.lastHour != lastHour && lastHour >= 0 && lastHour <= 23
  855. && lastHour >= getFirstVisibleHourOfDay()) {
  856. this.lastHour = lastHour;
  857. getState().lastHourOfDay = lastHour;
  858. }
  859. }
  860. /**
  861. * Returns the last visible hour in the week view. Returns the hour using a
  862. * 24h time format
  863. *
  864. */
  865. public int getLastVisibleHourOfDay() {
  866. return lastHour;
  867. }
  868. /**
  869. * Gets the date caption format for the weekly view.
  870. *
  871. * @return The pattern used in caption of dates in weekly view.
  872. */
  873. public String getWeeklyCaptionFormat() {
  874. return weeklyCaptionFormat;
  875. }
  876. /**
  877. * Sets custom date format for the weekly view. This is the caption of the
  878. * date. Format could be like "mmm MM/dd".
  879. *
  880. * @param dateFormatPattern
  881. * The date caption pattern.
  882. */
  883. public void setWeeklyCaptionFormat(String dateFormatPattern) {
  884. if (weeklyCaptionFormat == null && dateFormatPattern != null
  885. || weeklyCaptionFormat != null
  886. && !weeklyCaptionFormat.equals(dateFormatPattern)) {
  887. weeklyCaptionFormat = dateFormatPattern;
  888. markAsDirty();
  889. }
  890. }
  891. /**
  892. * Sets sort order for events. By default sort order is
  893. * {@link EventSortOrder#DURATION_DESC}.
  894. *
  895. * @param order
  896. * sort strategy for events
  897. */
  898. public void setEventSortOrder(EventSortOrder order) {
  899. if (order == null) {
  900. getState().eventSortOrder = EventSortOrder.DURATION_DESC;
  901. } else {
  902. getState().eventSortOrder = EventSortOrder.values()[order
  903. .ordinal()];
  904. }
  905. }
  906. /**
  907. * Returns sort order for events.
  908. *
  909. * @return currently active sort strategy
  910. */
  911. public EventSortOrder getEventSortOrder() {
  912. EventSortOrder order = getState(false).eventSortOrder;
  913. if (order == null) {
  914. return EventSortOrder.DURATION_DESC;
  915. } else {
  916. return order;
  917. }
  918. }
  919. private DateFormat getWeeklyCaptionFormatter() {
  920. if (weeklyCaptionFormat != null) {
  921. return new SimpleDateFormat(weeklyCaptionFormat, getLocale());
  922. } else {
  923. return SimpleDateFormat.getDateInstance(SimpleDateFormat.SHORT,
  924. getLocale());
  925. }
  926. }
  927. /**
  928. * Get the day of week by the given calendar and its locale
  929. *
  930. * @param calendar
  931. * The calendar to use
  932. * @return
  933. */
  934. private static int getDowByLocale(java.util.Calendar calendar) {
  935. int fow = calendar.get(java.util.Calendar.DAY_OF_WEEK);
  936. // monday first
  937. if (calendar.getFirstDayOfWeek() == java.util.Calendar.MONDAY) {
  938. fow = fow == java.util.Calendar.SUNDAY ? 7 : fow - 1;
  939. }
  940. return fow;
  941. }
  942. /**
  943. * Is the user allowed to trigger events which alters the events.
  944. *
  945. * @return true if the client is allowed to send changes to server
  946. * @see #isEventClickAllowed()
  947. */
  948. protected boolean isClientChangeAllowed() {
  949. return !isReadOnly();
  950. }
  951. /**
  952. * Is the user allowed to trigger click events. Returns {@code true} by
  953. * default. Subclass can override this method to disallow firing event
  954. * clicks got from the client side.
  955. *
  956. * @return true if the client is allowed to click events
  957. * @see #isClientChangeAllowed()
  958. * @deprecated As of 7.4, override {@link #fireEventClick(Integer)} instead.
  959. */
  960. @Deprecated
  961. protected boolean isEventClickAllowed() {
  962. return true;
  963. }
  964. /**
  965. * Fires an event when the user selecing moving forward/backward in the
  966. * calendar.
  967. *
  968. * @param forward
  969. * True if the calendar moved forward else backward is assumed.
  970. */
  971. protected void fireNavigationEvent(boolean forward) {
  972. if (forward) {
  973. fireEvent(new ForwardEvent(this));
  974. } else {
  975. fireEvent(new BackwardEvent(this));
  976. }
  977. }
  978. /**
  979. * Fires an event move event to all server side move listeners.
  980. *
  981. * @param index
  982. * The index of the event in the events list
  983. * @param newFromDatetime
  984. * The changed from date time
  985. */
  986. protected void fireEventMove(int index, Date newFromDatetime) {
  987. MoveEvent event = new MoveEvent(this, events.get(index),
  988. newFromDatetime);
  989. if (calendarEventProvider instanceof EventMoveHandler) {
  990. // Notify event provider if it is an event move handler
  991. ((EventMoveHandler) calendarEventProvider).eventMove(event);
  992. }
  993. // Notify event move handler attached by using the
  994. // setHandler(EventMoveHandler) method
  995. fireEvent(event);
  996. }
  997. /**
  998. * Fires event when a week was clicked in the calendar.
  999. *
  1000. * @param week
  1001. * The week that was clicked
  1002. * @param year
  1003. * The year of the week
  1004. */
  1005. protected void fireWeekClick(int week, int year) {
  1006. fireEvent(new WeekClick(this, week, year));
  1007. }
  1008. /**
  1009. * Fires event when a date was clicked in the calendar. Uses an existing
  1010. * event from the event cache.
  1011. *
  1012. * @param index
  1013. * The index of the event in the event cache.
  1014. */
  1015. protected void fireEventClick(Integer index) {
  1016. fireEvent(new EventClick(this, events.get(index)));
  1017. }
  1018. /**
  1019. * Fires event when a date was clicked in the calendar. Creates a new event
  1020. * for the date and passes it to the listener.
  1021. *
  1022. * @param date
  1023. * The date and time that was clicked
  1024. */
  1025. protected void fireDateClick(Date date) {
  1026. fireEvent(new DateClickEvent(this, date));
  1027. }
  1028. /**
  1029. * Fires an event range selected event. The event is fired when a user
  1030. * highlights an area in the calendar. The highlighted areas start and end
  1031. * dates are returned as arguments.
  1032. *
  1033. * @param from
  1034. * The start date and time of the highlighted area
  1035. * @param to
  1036. * The end date and time of the highlighted area
  1037. * @param monthlyMode
  1038. * Is the calendar in monthly mode
  1039. */
  1040. protected void fireRangeSelect(Date from, Date to, boolean monthlyMode) {
  1041. fireEvent(new RangeSelectEvent(this, from, to, monthlyMode));
  1042. }
  1043. /**
  1044. * Fires an event resize event. The event is fired when a user resizes the
  1045. * event in the calendar causing the time range of the event to increase or
  1046. * decrease. The new start and end times are returned as arguments to this
  1047. * method.
  1048. *
  1049. * @param index
  1050. * The index of the event in the event cache
  1051. * @param startTime
  1052. * The new start date and time of the event
  1053. * @param endTime
  1054. * The new end date and time of the event
  1055. */
  1056. protected void fireEventResize(int index, Date startTime, Date endTime) {
  1057. EventResize event = new EventResize(this, events.get(index), startTime,
  1058. endTime);
  1059. if (calendarEventProvider instanceof EventResizeHandler) {
  1060. // Notify event provider if it is an event resize handler
  1061. ((EventResizeHandler) calendarEventProvider).eventResize(event);
  1062. }
  1063. // Notify event resize handler attached by using the
  1064. // setHandler(EventMoveHandler) method
  1065. fireEvent(event);
  1066. }
  1067. /**
  1068. * Localized display names for week days starting from sunday. Returned
  1069. * array's length is always 7.
  1070. *
  1071. * @return Array of localized weekday names.
  1072. */
  1073. protected String[] getDayNamesShort() {
  1074. DateFormatSymbols s = new DateFormatSymbols(getLocale());
  1075. return Arrays.copyOfRange(s.getWeekdays(), 1, 8);
  1076. }
  1077. /**
  1078. * Localized display names for months starting from January. Returned
  1079. * array's length is always 12.
  1080. *
  1081. * @return Array of localized month names.
  1082. */
  1083. protected String[] getMonthNamesShort() {
  1084. DateFormatSymbols s = new DateFormatSymbols(getLocale());
  1085. return Arrays.copyOf(s.getShortMonths(), 12);
  1086. }
  1087. /**
  1088. * Gets a date that is first day in the week that target given date belongs
  1089. * to.
  1090. *
  1091. * @param date
  1092. * Target date
  1093. * @return Date that is first date in same week that given date is.
  1094. */
  1095. protected Date getFirstDateForWeek(Date date) {
  1096. int firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
  1097. currentCalendar.setTime(date);
  1098. while (firstDayOfWeek != currentCalendar
  1099. .get(java.util.Calendar.DAY_OF_WEEK)) {
  1100. currentCalendar.add(java.util.Calendar.DATE, -1);
  1101. }
  1102. return currentCalendar.getTime();
  1103. }
  1104. /**
  1105. * Gets a date that is last day in the week that target given date belongs
  1106. * to.
  1107. *
  1108. * @param date
  1109. * Target date
  1110. * @return Date that is last date in same week that given date is.
  1111. */
  1112. protected Date getLastDateForWeek(Date date) {
  1113. currentCalendar.setTime(date);
  1114. currentCalendar.add(java.util.Calendar.DATE, 1);
  1115. int firstDayOfWeek = currentCalendar.getFirstDayOfWeek();
  1116. // Roll to weeks last day using firstdayofweek. Roll until FDofW is
  1117. // found and then roll back one day.
  1118. while (firstDayOfWeek != currentCalendar
  1119. .get(java.util.Calendar.DAY_OF_WEEK)) {
  1120. currentCalendar.add(java.util.Calendar.DATE, 1);
  1121. }
  1122. currentCalendar.add(java.util.Calendar.DATE, -1);
  1123. return currentCalendar.getTime();
  1124. }
  1125. /**
  1126. * Calculates the end time of the day using the given calendar and date
  1127. *
  1128. * @param date
  1129. * @param calendar
  1130. * the calendar instance to be used in the calculation. The given
  1131. * instance is unchanged in this operation.
  1132. * @return the given date, with time set to the end of the day
  1133. */
  1134. private static Date getEndOfDay(java.util.Calendar calendar, Date date) {
  1135. java.util.Calendar calendarClone = (java.util.Calendar) calendar
  1136. .clone();
  1137. calendarClone.setTime(date);
  1138. calendarClone.set(java.util.Calendar.MILLISECOND,
  1139. calendarClone.getActualMaximum(java.util.Calendar.MILLISECOND));
  1140. calendarClone.set(java.util.Calendar.SECOND,
  1141. calendarClone.getActualMaximum(java.util.Calendar.SECOND));
  1142. calendarClone.set(java.util.Calendar.MINUTE,
  1143. calendarClone.getActualMaximum(java.util.Calendar.MINUTE));
  1144. calendarClone.set(java.util.Calendar.HOUR,
  1145. calendarClone.getActualMaximum(java.util.Calendar.HOUR));
  1146. calendarClone.set(java.util.Calendar.HOUR_OF_DAY,
  1147. calendarClone.getActualMaximum(java.util.Calendar.HOUR_OF_DAY));
  1148. return calendarClone.getTime();
  1149. }
  1150. /**
  1151. * Calculates the end time of the day using the given calendar and date
  1152. *
  1153. * @param date
  1154. * @param calendar
  1155. * the calendar instance to be used in the calculation. The given
  1156. * instance is unchanged in this operation.
  1157. * @return the given date, with time set to the end of the day
  1158. */
  1159. private static Date getStartOfDay(java.util.Calendar calendar, Date date) {
  1160. java.util.Calendar calendarClone = (java.util.Calendar) calendar
  1161. .clone();
  1162. calendarClone.setTime(date);
  1163. calendarClone.set(java.util.Calendar.MILLISECOND, 0);
  1164. calendarClone.set(java.util.Calendar.SECOND, 0);
  1165. calendarClone.set(java.util.Calendar.MINUTE, 0);
  1166. calendarClone.set(java.util.Calendar.HOUR, 0);
  1167. calendarClone.set(java.util.Calendar.HOUR_OF_DAY, 0);
  1168. return calendarClone.getTime();
  1169. }
  1170. /**
  1171. * Finds the first day of the week and returns a day representing the start
  1172. * of that day.
  1173. *
  1174. * @param start
  1175. * The actual date
  1176. * @param expandToFullWeek
  1177. * Should the returned date be moved to the start of the week
  1178. * @return If expandToFullWeek is set then it returns the first day of the
  1179. * week, else it returns a clone of the actual date with the time
  1180. * set to the start of the day
  1181. */
  1182. protected Date expandStartDate(Date start, boolean expandToFullWeek) {
  1183. // If the duration is more than week, use monthly view and get startweek
  1184. // and endweek. Example if views daterange is from tuesday to next weeks
  1185. // wednesday->expand to monday to nextweeks sunday. If firstdayofweek =
  1186. // monday
  1187. if (expandToFullWeek) {
  1188. start = getFirstDateForWeek(start);
  1189. } else {
  1190. start = (Date) start.clone();
  1191. }
  1192. // Always expand to the start of the first day to the end of the last
  1193. // day
  1194. start = getStartOfDay(currentCalendar, start);
  1195. return start;
  1196. }
  1197. /**
  1198. * Finds the last day of the week and returns a day representing the end of
  1199. * that day.
  1200. *
  1201. * @param end
  1202. * The actual date
  1203. * @param expandToFullWeek
  1204. * Should the returned date be moved to the end of the week
  1205. * @return If expandToFullWeek is set then it returns the last day of the
  1206. * week, else it returns a clone of the actual date with the time
  1207. * set to the end of the day
  1208. */
  1209. protected Date expandEndDate(Date end, boolean expandToFullWeek) {
  1210. // If the duration is more than week, use monthly view and get startweek
  1211. // and endweek. Example if views daterange is from tuesday to next weeks
  1212. // wednesday->expand to monday to nextweeks sunday. If firstdayofweek =
  1213. // monday
  1214. if (expandToFullWeek) {
  1215. end = getLastDateForWeek(end);
  1216. } else {
  1217. end = (Date) end.clone();
  1218. }
  1219. // Always expand to the start of the first day to the end of the last
  1220. // day
  1221. end = getEndOfDay(currentCalendar, end);
  1222. return end;
  1223. }
  1224. /**
  1225. * Set the {@link CalendarEventProvider} to be used with this calendar. The
  1226. * EventProvider is used to query for events to show, and must be non-null.
  1227. * By default a {@link BasicEventProvider} is used.
  1228. *
  1229. * @param calendarEventProvider
  1230. * the calendarEventProvider to set. Cannot be null.
  1231. */
  1232. public void setEventProvider(CalendarEventProvider calendarEventProvider) {
  1233. if (calendarEventProvider == null) {
  1234. throw new IllegalArgumentException(
  1235. "Calendar event provider cannot be null");
  1236. }
  1237. // remove old listener
  1238. if (getEventProvider() instanceof EventSetChangeNotifier) {
  1239. ((EventSetChangeNotifier) getEventProvider())
  1240. .removeEventSetChangeListener(this);
  1241. }
  1242. this.calendarEventProvider = calendarEventProvider;
  1243. // add new listener
  1244. if (calendarEventProvider instanceof EventSetChangeNotifier) {
  1245. ((EventSetChangeNotifier) calendarEventProvider)
  1246. .addEventSetChangeListener(this);
  1247. }
  1248. }
  1249. /**
  1250. * @return the {@link CalendarEventProvider} currently used
  1251. */
  1252. public CalendarEventProvider getEventProvider() {
  1253. return calendarEventProvider;
  1254. }
  1255. @Override
  1256. public void eventSetChange(EventSetChangeEvent changeEvent) {
  1257. // sanity check
  1258. if (calendarEventProvider == changeEvent.getProvider()) {
  1259. markAsDirty();
  1260. }
  1261. }
  1262. /**
  1263. * Set the handler for the given type information. Mirrors
  1264. * {@link #addListener(String, Class, Object, Method) addListener} from
  1265. * AbstractComponent
  1266. *
  1267. * @param eventId
  1268. * A unique id for the event. Usually one of
  1269. * {@link CalendarEventId}
  1270. * @param eventType
  1271. * The class of the event, most likely a subclass of
  1272. * {@link CalendarComponentEvent}
  1273. * @param listener
  1274. * A listener that listens to the given event
  1275. * @param listenerMethod
  1276. * The method on the lister to call when the event is triggered
  1277. */
  1278. protected void setHandler(String eventId, Class<?> eventType,
  1279. EventListener listener, Method listenerMethod) {
  1280. if (handlers.get(eventId) != null) {
  1281. removeListener(eventId, eventType, handlers.get(eventId));
  1282. handlers.remove(eventId);
  1283. }
  1284. if (listener != null) {
  1285. addListener(eventId, eventType, listener, listenerMethod);
  1286. handlers.put(eventId, listener);
  1287. }
  1288. }
  1289. @Override
  1290. public void setHandler(ForwardHandler listener) {
  1291. setHandler(ForwardEvent.EVENT_ID, ForwardEvent.class, listener,
  1292. ForwardHandler.forwardMethod);
  1293. }
  1294. @Override
  1295. public void setHandler(BackwardHandler listener) {
  1296. setHandler(BackwardEvent.EVENT_ID, BackwardEvent.class, listener,
  1297. BackwardHandler.backwardMethod);
  1298. }
  1299. @Override
  1300. public void setHandler(DateClickHandler listener) {
  1301. setHandler(DateClickEvent.EVENT_ID, DateClickEvent.class, listener,
  1302. DateClickHandler.dateClickMethod);
  1303. }
  1304. @Override
  1305. public void setHandler(EventClickHandler listener) {
  1306. setHandler(EventClick.EVENT_ID, EventClick.class, listener,
  1307. EventClickHandler.eventClickMethod);
  1308. }
  1309. @Override
  1310. public void setHandler(WeekClickHandler listener) {
  1311. setHandler(WeekClick.EVENT_ID, WeekClick.class, listener,
  1312. WeekClickHandler.weekClickMethod);
  1313. }
  1314. @Override
  1315. public void setHandler(EventResizeHandler listener) {
  1316. setHandler(EventResize.EVENT_ID, EventResize.class, listener,
  1317. EventResizeHandler.eventResizeMethod);
  1318. }
  1319. @Override
  1320. public void setHandler(RangeSelectHandler listener) {
  1321. setHandler(RangeSelectEvent.EVENT_ID, RangeSelectEvent.class, listener,
  1322. RangeSelectHandler.rangeSelectMethod);
  1323. }
  1324. @Override
  1325. public void setHandler(EventMoveHandler listener) {
  1326. setHandler(MoveEvent.EVENT_ID, MoveEvent.class, listener,
  1327. EventMoveHandler.eventMoveMethod);
  1328. }
  1329. @Override
  1330. public EventListener getHandler(String eventId) {
  1331. return handlers.get(eventId);
  1332. }
  1333. /**
  1334. * Get the currently active drop handler.
  1335. */
  1336. @Override
  1337. public DropHandler getDropHandler() {
  1338. return dropHandler;
  1339. }
  1340. /**
  1341. * Set the drop handler for the calendar See {@link DropHandler} for
  1342. * implementation details.
  1343. *
  1344. * @param dropHandler
  1345. * The drop handler to set
  1346. */
  1347. public void setDropHandler(DropHandler dropHandler) {
  1348. this.dropHandler = dropHandler;
  1349. }
  1350. @Override
  1351. public TargetDetails translateDropTargetDetails(
  1352. Map<String, Object> clientVariables) {
  1353. Map<String, Object> serverVariables = new HashMap<String, Object>();
  1354. if (clientVariables.containsKey("dropSlotIndex")) {
  1355. int slotIndex = (Integer) clientVariables.get("dropSlotIndex");
  1356. int dayIndex = (Integer) clientVariables.get("dropDayIndex");
  1357. currentCalendar.setTime(getStartOfDay(currentCalendar, startDate));
  1358. currentCalendar.add(java.util.Calendar.DATE, dayIndex);
  1359. // change this if slot length is modified
  1360. currentCalendar.add(java.util.Calendar.MINUTE, slotIndex * 30);
  1361. serverVariables.put("dropTime", currentCalendar.getTime());
  1362. } else {
  1363. int dayIndex = (Integer) clientVariables.get("dropDayIndex");
  1364. currentCalendar.setTime(expandStartDate(startDate, true));
  1365. currentCalendar.add(java.util.Calendar.DATE, dayIndex);
  1366. serverVariables.put("dropDay", currentCalendar.getTime());
  1367. }
  1368. serverVariables.put("mouseEvent", clientVariables.get("mouseEvent"));
  1369. CalendarTargetDetails td = new CalendarTargetDetails(serverVariables,
  1370. this);
  1371. td.setHasDropTime(clientVariables.containsKey("dropSlotIndex"));
  1372. return td;
  1373. }
  1374. /**
  1375. * Sets a container as a data source for the events in the calendar.
  1376. * Equivalent for doing
  1377. * <code>Calendar.setEventProvider(new ContainerEventProvider(container))</code>
  1378. *
  1379. * Use this method if you are adding a container which uses the default
  1380. * property ids like {@link BeanItemContainer} for instance. If you are
  1381. * using custom properties instead use
  1382. * {@link Calendar#setContainerDataSource(Container.Indexed, Object, Object, Object, Object, Object)}
  1383. *
  1384. * Please note that the container must be sorted by date!
  1385. *
  1386. * @param container
  1387. * The container to use as a datasource
  1388. */
  1389. public void setContainerDataSource(Container.Indexed container) {
  1390. ContainerEventProvider provider = new ContainerEventProvider(container);
  1391. provider.addEventSetChangeListener(
  1392. new CalendarEventProvider.EventSetChangeListener() {
  1393. @Override
  1394. public void eventSetChange(
  1395. EventSetChangeEvent changeEvent) {
  1396. // Repaint if events change
  1397. markAsDirty();
  1398. }
  1399. });
  1400. provider.addEventChangeListener(new EventChangeListener() {
  1401. @Override
  1402. public void eventChange(EventChangeEvent changeEvent) {
  1403. // Repaint if event changes
  1404. markAsDirty();
  1405. }
  1406. });
  1407. setEventProvider(provider);
  1408. }
  1409. /**
  1410. * Sets a container as a data source for the events in the calendar.
  1411. * Equivalent for doing
  1412. * <code>Calendar.setEventProvider(new ContainerEventProvider(container))</code>
  1413. *
  1414. * Please note that the container must be sorted by date!
  1415. *
  1416. * @param container
  1417. * The container to use as a data source
  1418. * @param captionProperty
  1419. * The property that has the caption, null if no caption property
  1420. * is present
  1421. * @param descriptionProperty
  1422. * The property that has the description, null if no description
  1423. * property is present
  1424. * @param startDateProperty
  1425. * The property that has the starting date
  1426. * @param endDateProperty
  1427. * The property that has the ending date
  1428. * @param styleNameProperty
  1429. * The property that has the stylename, null if no stylname
  1430. * property is present
  1431. */
  1432. public void setContainerDataSource(Container.Indexed container,
  1433. Object captionProperty, Object descriptionProperty,
  1434. Object startDateProperty, Object endDateProperty,
  1435. Object styleNameProperty) {
  1436. ContainerEventProvider provider = new ContainerEventProvider(container);
  1437. provider.setCaptionProperty(captionProperty);
  1438. provider.setDescriptionProperty(descriptionProperty);
  1439. provider.setStartDateProperty(startDateProperty);
  1440. provider.setEndDateProperty(endDateProperty);
  1441. provider.setStyleNameProperty(styleNameProperty);
  1442. provider.addEventSetChangeListener(
  1443. new CalendarEventProvider.EventSetChangeListener() {
  1444. @Override
  1445. public void eventSetChange(
  1446. EventSetChangeEvent changeEvent) {
  1447. // Repaint if events change
  1448. markAsDirty();
  1449. }
  1450. });
  1451. provider.addEventChangeListener(new EventChangeListener() {
  1452. @Override
  1453. public void eventChange(EventChangeEvent changeEvent) {
  1454. // Repaint if event changes
  1455. markAsDirty();
  1456. }
  1457. });
  1458. setEventProvider(provider);
  1459. }
  1460. @Override
  1461. public List<CalendarEvent> getEvents(Date startDate, Date endDate) {
  1462. List<CalendarEvent> events = getEventProvider().getEvents(startDate,
  1463. endDate);
  1464. cacheMinMaxTimeOfDay(events);
  1465. return events;
  1466. }
  1467. @Override
  1468. public void addEvent(CalendarEvent event) {
  1469. if (getEventProvider() instanceof CalendarEditableEventProvider) {
  1470. CalendarEditableEventProvider provider = (CalendarEditableEventProvider) getEventProvider();
  1471. provider.addEvent(event);
  1472. markAsDirty();
  1473. } else {
  1474. throw new UnsupportedOperationException(
  1475. "Event provider does not support adding events");
  1476. }
  1477. }
  1478. @Override
  1479. public void removeEvent(CalendarEvent event) {
  1480. if (getEventProvider() instanceof CalendarEditableEventProvider) {
  1481. CalendarEditableEventProvider provider = (CalendarEditableEventProvider) getEventProvider();
  1482. provider.removeEvent(event);
  1483. markAsDirty();
  1484. } else {
  1485. throw new UnsupportedOperationException(
  1486. "Event provider does not support removing events");
  1487. }
  1488. }
  1489. /**
  1490. * Adds an action handler to the calendar that handles event produced by the
  1491. * context menu.
  1492. *
  1493. * <p>
  1494. * The {@link Handler#getActions(Object, Object)} parameters depend on what
  1495. * view the Calendar is in:
  1496. * <ul>
  1497. * <li>If the Calendar is in <i>Day or Week View</i> then the target
  1498. * parameter will be a {@link CalendarDateRange} with a range of
  1499. * half-an-hour. The {@link Handler#getActions(Object, Object)} method will
  1500. * be called once per half-hour slot.</li>
  1501. * <li>If the Calendar is in <i>Month View</i> then the target parameter
  1502. * will be a {@link CalendarDateRange} with a range of one day. The
  1503. * {@link Handler#getActions(Object, Object)} will be called once for each
  1504. * day.
  1505. * </ul>
  1506. * The Dates passed into the {@link CalendarDateRange} are in the same
  1507. * timezone as the calendar is.
  1508. * </p>
  1509. *
  1510. * <p>
  1511. * The {@link Handler#handleAction(Action, Object, Object)} parameters
  1512. * depend on what the context menu is called upon:
  1513. * <ul>
  1514. * <li>If the context menu is called upon an event then the target parameter
  1515. * is the event, i.e. instanceof {@link CalendarEvent}</li>
  1516. * <li>If the context menu is called upon an empty slot then the target is a
  1517. * {@link Date} representing that slot
  1518. * </ul>
  1519. * </p>
  1520. */
  1521. @Override
  1522. public void addActionHandler(Handler actionHandler) {
  1523. if (actionHandler != null) {
  1524. if (actionHandlers == null) {
  1525. actionHandlers = new LinkedList<Handler>();
  1526. actionMapper = new KeyMapper<Action>();
  1527. }
  1528. if (!actionHandlers.contains(actionHandler)) {
  1529. actionHandlers.add(actionHandler);
  1530. markAsDirty();
  1531. }
  1532. }
  1533. }
  1534. /**
  1535. * Is the calendar in a mode where all days of the month is shown.
  1536. *
  1537. * @return Returns true if calendar is in monthly mode and false if it is in
  1538. * weekly mode
  1539. */
  1540. public boolean isMonthlyMode() {
  1541. CalendarState state = getState(false);
  1542. if (state.days != null) {
  1543. return state.days.size() > 7;
  1544. } else {
  1545. // Default mode
  1546. return true;
  1547. }
  1548. }
  1549. @Override
  1550. public void removeActionHandler(Handler actionHandler) {
  1551. if (actionHandlers != null && actionHandlers.contains(actionHandler)) {
  1552. actionHandlers.remove(actionHandler);
  1553. if (actionHandlers.isEmpty()) {
  1554. actionHandlers = null;
  1555. actionMapper = null;
  1556. }
  1557. markAsDirty();
  1558. }
  1559. }
  1560. private class CalendarServerRpcImpl implements CalendarServerRpc {
  1561. @Override
  1562. public void eventMove(int eventIndex, String newDate) {
  1563. if (!isClientChangeAllowed()) {
  1564. return;
  1565. }
  1566. if (newDate != null) {
  1567. try {
  1568. Date d = df_date_time.parse(newDate);
  1569. if (eventIndex >= 0 && eventIndex < events.size()
  1570. && events.get(eventIndex) != null) {
  1571. fireEventMove(eventIndex, d);
  1572. }
  1573. } catch (ParseException e) {
  1574. getLogger().log(Level.WARNING, e.getMessage());
  1575. }
  1576. }
  1577. }
  1578. @Override
  1579. public void rangeSelect(String range) {
  1580. if (!isClientChangeAllowed()) {
  1581. return;
  1582. }
  1583. if (range != null && range.length() > 14 && range.contains("TO")) {
  1584. String[] dates = range.split("TO");
  1585. try {
  1586. Date d1 = df_date.parse(dates[0]);
  1587. Date d2 = df_date.parse(dates[1]);
  1588. fireRangeSelect(d1, d2, true);
  1589. } catch (ParseException e) {
  1590. // NOP
  1591. }
  1592. } else if (range != null && range.length() > 12
  1593. && range.contains(":")) {
  1594. String[] dates = range.split(":");
  1595. if (dates.length == 3) {
  1596. try {
  1597. Date d = df_date.parse(dates[0]);
  1598. currentCalendar.setTime(d);
  1599. int startMinutes = Integer.parseInt(dates[1]);
  1600. int endMinutes = Integer.parseInt(dates[2]);
  1601. currentCalendar.add(java.util.Calendar.MINUTE,
  1602. startMinutes);
  1603. Date start = currentCalendar.getTime();
  1604. currentCalendar.add(java.util.Calendar.MINUTE,
  1605. endMinutes - startMinutes);
  1606. Date end = currentCalendar.getTime();
  1607. fireRangeSelect(start, end, false);
  1608. } catch (ParseException e) {
  1609. // NOP
  1610. } catch (NumberFormatException e) {
  1611. // NOP
  1612. }
  1613. }
  1614. }
  1615. }
  1616. @Override
  1617. public void forward() {
  1618. fireEvent(new ForwardEvent(Calendar.this));
  1619. }
  1620. @Override
  1621. public void backward() {
  1622. fireEvent(new BackwardEvent(Calendar.this));
  1623. }
  1624. @Override
  1625. public void dateClick(String date) {
  1626. if (date != null && date.length() > 6) {
  1627. try {
  1628. Date d = df_date.parse(date);
  1629. fireDateClick(d);
  1630. } catch (ParseException e) {
  1631. }
  1632. }
  1633. }
  1634. @Override
  1635. public void weekClick(String event) {
  1636. if (!event.isEmpty() && event.contains("w")) {
  1637. String[] splitted = event.split("w");
  1638. if (splitted.length == 2) {
  1639. try {
  1640. int yr = Integer.parseInt(splitted[0]);
  1641. int week = Integer.parseInt(splitted[1]);
  1642. fireWeekClick(week, yr);
  1643. } catch (NumberFormatException e) {
  1644. // NOP
  1645. }
  1646. }
  1647. }
  1648. }
  1649. @Override
  1650. public void eventClick(int eventIndex) {
  1651. if (!isEventClickAllowed()) {
  1652. return;
  1653. }
  1654. if (eventIndex >= 0 && eventIndex < events.size()
  1655. && events.get(eventIndex) != null) {
  1656. fireEventClick(eventIndex);
  1657. }
  1658. }
  1659. @Override
  1660. public void eventResize(int eventIndex, String newStartDate,
  1661. String newEndDate) {
  1662. if (!isClientChangeAllowed()) {
  1663. return;
  1664. }
  1665. if (newStartDate != null && !"".equals(newStartDate)
  1666. && newEndDate != null && !"".equals(newEndDate)) {
  1667. try {
  1668. Date newStartTime = df_date_time.parse(newStartDate);
  1669. Date newEndTime = df_date_time.parse(newEndDate);
  1670. fireEventResize(eventIndex, newStartTime, newEndTime);
  1671. } catch (ParseException e) {
  1672. // NOOP
  1673. }
  1674. }
  1675. }
  1676. @Override
  1677. public void scroll(int scrollPosition) {
  1678. scrollTop = scrollPosition;
  1679. markAsDirty();
  1680. }
  1681. @Override
  1682. public void actionOnEmptyCell(String actionKey, String startDate,
  1683. String endDate) {
  1684. Action action = actionMapper.get(actionKey);
  1685. SimpleDateFormat formatter = new SimpleDateFormat(
  1686. DateConstants.ACTION_DATE_FORMAT_PATTERN);
  1687. formatter.setTimeZone(getTimeZone());
  1688. try {
  1689. Date start = formatter.parse(startDate);
  1690. for (Action.Handler ah : actionHandlers) {
  1691. ah.handleAction(action, Calendar.this, start);
  1692. }
  1693. } catch (ParseException e) {
  1694. getLogger().log(Level.WARNING,
  1695. "Could not parse action date string");
  1696. }
  1697. }
  1698. @Override
  1699. public void actionOnEvent(String actionKey, String startDate,
  1700. String endDate, int eventIndex) {
  1701. Action action = actionMapper.get(actionKey);
  1702. SimpleDateFormat formatter = new SimpleDateFormat(
  1703. DateConstants.ACTION_DATE_FORMAT_PATTERN);
  1704. formatter.setTimeZone(getTimeZone());
  1705. for (Action.Handler ah : actionHandlers) {
  1706. ah.handleAction(action, Calendar.this, events.get(eventIndex));
  1707. }
  1708. }
  1709. }
  1710. @Override
  1711. public void changeVariables(Object source, Map<String, Object> variables) {
  1712. /*
  1713. * Only defined to fulfill the LegacyComponent interface used for
  1714. * calendar drag & drop. No implementation required.
  1715. */
  1716. }
  1717. @Override
  1718. public void paintContent(PaintTarget target) throws PaintException {
  1719. if (dropHandler != null) {
  1720. dropHandler.getAcceptCriterion().paint(target);
  1721. }
  1722. }
  1723. /**
  1724. * Sets whether the event captions are rendered as HTML.
  1725. * <p>
  1726. * If set to true, the captions are rendered in the browser as HTML and the
  1727. * developer is responsible for ensuring no harmful HTML is used. If set to
  1728. * false, the caption is rendered in the browser as plain text.
  1729. * <p>
  1730. * The default is false, i.e. to render that caption as plain text.
  1731. *
  1732. * @param eventCaptionAsHtml
  1733. * {@code true} if the captions are rendered as HTML,
  1734. * {@code false} if rendered as plain text
  1735. */
  1736. public void setEventCaptionAsHtml(boolean eventCaptionAsHtml) {
  1737. getState().eventCaptionAsHtml = eventCaptionAsHtml;
  1738. }
  1739. /**
  1740. * Checks whether event captions are rendered as HTML
  1741. * <p>
  1742. * The default is false, i.e. to render that caption as plain text.
  1743. *
  1744. * @return true if the captions are rendered as HTML, false if rendered as
  1745. * plain text
  1746. */
  1747. public boolean isEventCaptionAsHtml() {
  1748. return getState(false).eventCaptionAsHtml;
  1749. }
  1750. @Override
  1751. public void readDesign(Element design, DesignContext designContext) {
  1752. super.readDesign(design, designContext);
  1753. Attributes attr = design.attributes();
  1754. if (design.hasAttr("time-format")) {
  1755. setTimeFormat(TimeFormat.valueOf(
  1756. "Format" + design.attr("time-format").toUpperCase()));
  1757. }
  1758. if (design.hasAttr("start-date")) {
  1759. setStartDate(DesignAttributeHandler.readAttribute("start-date",
  1760. attr, Date.class));
  1761. }
  1762. if (design.hasAttr("end-date")) {
  1763. setEndDate(DesignAttributeHandler.readAttribute("end-date", attr,
  1764. Date.class));
  1765. }
  1766. };
  1767. @Override
  1768. public void writeDesign(Element design, DesignContext designContext) {
  1769. super.writeDesign(design, designContext);
  1770. if (currentTimeFormat != null) {
  1771. design.attr("time-format",
  1772. currentTimeFormat == TimeFormat.Format12H ? "12h" : "24h");
  1773. }
  1774. if (startDate != null) {
  1775. design.attr("start-date", df_date.format(getStartDate()));
  1776. }
  1777. if (endDate != null) {
  1778. design.attr("end-date", df_date.format(getEndDate()));
  1779. }
  1780. if (!getTimeZone().equals(TimeZone.getDefault())) {
  1781. design.attr("time-zone", getTimeZone().getID());
  1782. }
  1783. }
  1784. @Override
  1785. protected Collection<String> getCustomAttributes() {
  1786. Collection<String> customAttributes = super.getCustomAttributes();
  1787. customAttributes.add("time-format");
  1788. customAttributes.add("start-date");
  1789. customAttributes.add("end-date");
  1790. return customAttributes;
  1791. }
  1792. /**
  1793. * Allow setting first day of week independent of Locale. Set to null if you
  1794. * want first day of week being defined by the locale
  1795. *
  1796. * @since 7.6
  1797. * @param dayOfWeek
  1798. * any of java.util.Calendar.SUNDAY..java.util.Calendar.SATURDAY
  1799. * or null to revert to default first day of week by locale
  1800. */
  1801. public void setFirstDayOfWeek(Integer dayOfWeek) {
  1802. int minimalSupported = java.util.Calendar.SUNDAY;
  1803. int maximalSupported = java.util.Calendar.SATURDAY;
  1804. if (dayOfWeek != null && (dayOfWeek < minimalSupported
  1805. || dayOfWeek > maximalSupported)) {
  1806. throw new IllegalArgumentException(String.format(
  1807. "Day of week must be between %s and %s. Actually received: %s",
  1808. minimalSupported, maximalSupported, dayOfWeek));
  1809. }
  1810. customFirstDayOfWeek = dayOfWeek;
  1811. markAsDirty();
  1812. }
  1813. }