Java tutorial
/** * OLAT - Online Learning and Training<br> * http://www.olat.org * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Copyright (c) since 2004 at Multimedia- & E-Learning Services (MELS),<br> * University of Zurich, Switzerland. * <p> */ package org.olat.commons.calendar.ui.components; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.time.DateUtils; import org.olat.commons.calendar.CalendarManager; import org.olat.commons.calendar.CalendarUtils; import org.olat.commons.calendar.model.KalendarEvent; import org.olat.commons.calendar.model.KalendarEventLink; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.ComponentRenderer; import org.olat.core.gui.control.winmgr.AJAXFlags; import org.olat.core.gui.render.RenderResult; import org.olat.core.gui.render.Renderer; import org.olat.core.gui.render.RenderingState; import org.olat.core.gui.render.StringOutput; import org.olat.core.gui.render.URLBuilder; import org.olat.core.gui.translator.Translator; import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.core.util.Util; public class WeeklyCalendarComponentRenderer implements ComponentRenderer { /* This is fix (see calendar.css) */ private int days = 7; private int viewStartHour = 7; /* This is fix (and depends on settings in calendar.css) */ private static int dayEventHeightPixels = 20; private static int halfHourHeightPixels = 20; private static float dayGridRelativeStart = 9; private static float dayRelativeWidth = 13; private final DateFormat dmyDateFormat = new SimpleDateFormat("ddMMyyyyHHmm"); private boolean isIframePostEnabled = false; public WeeklyCalendarComponentRenderer(final int viewStartHour) { this.viewStartHour = viewStartHour; } public void render(final Renderer renderer, final StringOutput sb, final Component source, final URLBuilder ubu, final Translator translator, final RenderResult renderResult, final String[] args) { final WeeklyCalendarComponent calendarComponent = (WeeklyCalendarComponent) source; days = calendarComponent.getDisplayDays(); final int year = calendarComponent.getYear(); final int weekOfYear = calendarComponent.getWeekOfYear(); isIframePostEnabled = renderer.getGlobalSettings().getAjaxFlags().isIframePostEnabled(); // get all events from all calendars within the week's view // sort into standard events and allday events // sort both arrays final Calendar cal = CalendarUtils.getStartOfWeekCalendar(calendarComponent.getYear(), calendarComponent.getWeekOfYear(), translator.getLocale()); final Date weekStart = cal.getTime(); cal.add(Calendar.DAY_OF_YEAR, days); final Date weekEnd = cal.getTime(); final List<KalendarEventRenderWrapper> sortedEventsWithinWeek = new ArrayList<KalendarEventRenderWrapper>(); final List<KalendarEventRenderWrapper> sortedAllDayEventsWithinWeek = new ArrayList<KalendarEventRenderWrapper>(); boolean hasWriteableCalendar = false; for (final Iterator kalendarWrappers = calendarComponent.getKalendars().iterator(); kalendarWrappers .hasNext();) { final KalendarRenderWrapper calendarWrapper = (KalendarRenderWrapper) kalendarWrappers.next(); // check if calendar is writeable if (calendarWrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) { hasWriteableCalendar = true; } // skip if not selected for display if (!calendarComponent.isEventAlwaysVisible() && !calendarWrapper.getKalendarConfig().isVis()) { continue; } final boolean readOnlyCalendar = calendarWrapper.getAccess() == KalendarRenderWrapper.ACCESS_READ_ONLY; final boolean isImportedCalendar = calendarWrapper.isImported(); final List events = CalendarUtils.listEventsForPeriod(calendarWrapper.getKalendar(), weekStart, weekEnd); for (final Iterator iter = events.iterator(); iter.hasNext();) { final KalendarEvent event = (KalendarEvent) iter.next(); // filter out private events on readonly calendars if (readOnlyCalendar && !isImportedCalendar && event.getClassification() == KalendarEvent.CLASS_PRIVATE) { continue; } if (event.isAllDayEvent()) { sortedAllDayEventsWithinWeek.add(new KalendarEventRenderWrapper(event, calendarWrapper)); } else { sortedEventsWithinWeek.add(new KalendarEventRenderWrapper(event, calendarWrapper)); } } } Collections.sort(sortedEventsWithinWeek, KalendarEventDateComparator.getInstance()); Collections.sort(sortedAllDayEventsWithinWeek, KalendarEventDateComparator.getInstance()); final Locale locale = translator.getLocale(); // open grid divs sb.append("\n<div class=\"o_cal_wv\" id=\"o_cal_wv\">"); // render the grid sb.append("<div id=\"o_cal_wv_header_wrapper\">"); renderWeekHeader(year, weekOfYear, hasWriteableCalendar, sb, ubu, locale); renderAllDayGrid(year, weekOfYear, sortedAllDayEventsWithinWeek, sb, ubu, translator); sb.append("</div><div class=\"o_cal_wv_grid_wrapper\"><div class=\"o_cal_wv_grid\" id=\"o_cal_wv_grid\">"); renderWeekGrid(year, weekOfYear, hasWriteableCalendar, sb, ubu, locale); // add events to grid, absolute positioned renderEvents(year, weekOfYear, sortedEventsWithinWeek, sb, ubu, locale); // close grid divs sb.append("</div></div></div>"); // optimize grid height and position scrollbar using ext.onready sb.append("<script type=\"text/javascript\">\n/* <![CDATA[ */\n"); sb.append("Ext.onReady(function(){\n"); sb.append("B_AjaxLogger.logDebug('onready','calendar');"); sb.append("o_adjustCalendarHeight(\"o_cal_wv_grid\", 960);\n"); sb.append("window.onresize = function() {o_adjustCalendarHeight(\"o_cal_wv_grid\", 960) };\n"); sb.append("o_positionScrollbar(\"o_cal_wv_grid\", ").append(viewStartHour * 2 * halfHourHeightPixels) .append(");\n"); sb.append("o_init_event_tooltips();"); sb.append("o_mark_event_box_overflow();"); sb.append("\n});"); sb.append("B_AjaxLogger.logDebug('right away','calendar');"); sb.append("\n/* ]]> */\n</script>"); // render print view final List<KalendarEventRenderWrapper> allEventsOfWeek = new ArrayList<KalendarEventRenderWrapper>( sortedAllDayEventsWithinWeek); allEventsOfWeek.addAll(sortedEventsWithinWeek); Collections.sort(allEventsOfWeek, KalendarEventDateComparator.getInstance()); renderEventsListForPrint(year, weekOfYear, allEventsOfWeek, sb, locale); } private void renderEventsListForPrint(final int year, final int weekOfYear, final List<KalendarEventRenderWrapper> sortedEventsWithinWeek, final StringOutput sb, final Locale locale) { sb.append("<div class=\"o_cal_wv_print\">\n"); sb.append("<ul class=\"o_cal_wv_list\">\n"); // render day events which are positioned absolute final Calendar cal = CalendarUtils.getStartOfWeekCalendar(year, weekOfYear, locale); Date periodStart = cal.getTime(); cal.add(Calendar.DAY_OF_YEAR, 1); Date periodEnd = cal.getTime(); // itterate over days for (int dayCounter = 0; dayCounter < days; dayCounter++) { // collect all events for actual day final List<KalendarEventRenderWrapper> sortedEventsOfDay = new ArrayList<KalendarEventRenderWrapper>(); for (final KalendarEventRenderWrapper eventWrapper : sortedEventsWithinWeek) { final KalendarEvent nextEvent = eventWrapper.getEvent(); if (nextEvent.getEnd().before(periodStart) || nextEvent.getBegin().after(periodEnd)) { continue; } sortedEventsOfDay.add(eventWrapper); } // note that eventWrappers may get re-used if it is a multi-day event renderEventsOfDayForPrint(sortedEventsOfDay, periodStart, periodEnd, sb, locale); // reposition start/end period periodStart = periodEnd; cal.add(Calendar.DAY_OF_YEAR, 1); periodEnd = cal.getTime(); } // day iteration sb.append("</ul>\n"); sb.append("<div class=\"b_clearfix\"> </div>\n"); sb.append("</div>\n"); } private void renderEventsOfDayForPrint(final List<KalendarEventRenderWrapper> sortedEvents, final Date dayStart, final Date dayEnd, final StringOutput sb, final Locale locale) { if (!sortedEvents.isEmpty()) { sb.append("<li>\n"); sb.append("<span class=\"o_cal_date\">\n"); sb.append(StringHelper.formatLocaleDateFull(dayStart.getTime(), locale)); sb.append("</span>\n"); sb.append("<ul class=\"o_cal_events\">\n"); for (final KalendarEventRenderWrapper event : sortedEvents) { renderEventForPrint(event, dayStart, dayEnd, sb, locale); } sb.append("</ul>\n"); sb.append("</li>\n"); } } private void renderEventForPrint(final KalendarEventRenderWrapper eventWrapper, final Date dayStart, final Date dayEnd, final StringOutput sb, final Locale locale) { final KalendarEvent event = eventWrapper.getEvent(); final boolean hidden = eventWrapper.getCalendarAccess() == KalendarRenderWrapper.ACCESS_READ_ONLY && !eventWrapper.getKalendarRenderWrapper().isImported() && event.getClassification() != KalendarEvent.CLASS_PUBLIC; String escapedSubject = Formatter.escWithBR(event.getSubject()).toString(); escapedSubject = escapedSubject.replace('\r', ' '); sb.append("<li class=\"o_cal_event\">\n"); // time sb.append("<div class=\"o_cal_time\"><span>\n"); final Translator translator = Util.createPackageTranslator(CalendarManager.class, locale); if (event.isAllDayEvent()) { sb.append(translator.translate("cal.form.allday")); } else { // set start and end times for events spanning more than one day Date begin = event.getBegin(); Date end = event.getEnd(); if (begin.before(dayStart)) { begin = dayStart; } if (end.after(dayEnd)) { end = dayEnd; } sb.append(StringHelper.formatLocaleTime(begin.getTime(), locale)); sb.append(" - "); sb.append(StringHelper.formatLocaleTime(end.getTime(), locale)); } sb.append("</span></div>\n"); // event name (subject) sb.append("<div class=\"o_cal_subject " + eventWrapper.getCssClass() + "\"><span>\n"); if (hidden) { sb.append("-"); } else { sb.append(escapedSubject); } sb.append("</span></div>\n"); // location if (StringHelper.containsNonWhitespace(event.getLocation())) { sb.append("<div class=\"o_cal_location\"><span>\n"); sb.append(translator.translate("cal.form.location") + ": "); if (!hidden) { sb.append(event.getLocation()); } sb.append("</span></div>\n"); } sb.append("</li>\n"); } private void renderAllDayGrid(final int year, final int weekOfYear, final List sortedAllDayEventsForWeek, final StringOutput sb, final URLBuilder ubu, final Translator translator) { final Calendar cal = CalendarUtils.getStartOfWeekCalendar(year, weekOfYear, translator.getLocale()); int dayToday = -1; final Calendar calNow = CalendarUtils.createCalendarInstance(translator.getLocale()); if ((calNow.get(Calendar.WEEK_OF_YEAR) == weekOfYear) && (calNow.get(Calendar.YEAR) == year)) { // if we are within current week, adjust dayToday dayToday = calNow.get(Calendar.DAY_OF_WEEK); } final StringOutput inset = new StringOutput(1024); int maxDayEvents = 0; for (int day = 1; day <= days; day++) { final int dayOfWeekIter = cal.get(Calendar.DAY_OF_WEEK); final Date periodBegin = cal.getTime(); inset.append("<div class=\"o_cal_wv_dlday o_cal_wv_row"); inset.append(day); if (dayOfWeekIter == dayToday) { // current day inset.append(" o_cal_wv_today"); } else if (dayOfWeekIter == Calendar.SATURDAY || dayOfWeekIter == Calendar.SUNDAY) { // holiday inset.append(" o_cal_wv_holiday"); } if (day == days) { // last day inset.append(" o_cal_wv_lastday"); } inset.append("\" style=\"height: 100%;\">"); cal.add(Calendar.DAY_OF_YEAR, 1); final Date periodEnd = cal.getTime(); // render daylong events int maxDayEventsThisDay = 0; for (final Iterator iter = sortedAllDayEventsForWeek.iterator(); iter.hasNext();) { final KalendarEventRenderWrapper eventWrapper = (KalendarEventRenderWrapper) iter.next(); final KalendarEvent event = eventWrapper.getEvent(); // skip if not within period if (event.getEnd().compareTo(periodBegin) < 0 || event.getBegin().compareTo(periodEnd) >= 0) { continue; } // increment count of number of dayevents maxDayEventsThisDay++; final boolean hideSubject = eventWrapper .getCalendarAccess() == KalendarRenderWrapper.ACCESS_READ_ONLY && !eventWrapper.getKalendarRenderWrapper().isImported() && event.getClassification() != KalendarEvent.CLASS_PUBLIC; final String escapedSubject = Formatter.escWithBR(event.getSubject()).toString(); inset.append("<div class=\"o_cal_wv_devent_wrapper\">"); inset.append("<div class=\"o_cal_wv_devent ") .append(eventWrapper.getKalendarRenderWrapper().getKalendarConfig().getCss()).append("\">"); inset.append("<div class=\"o_cal_wv_devent_content\">"); inset.append("<a href=\""); ubu.buildURI(inset, new String[] { WeeklyCalendarComponent.ID_CMD, WeeklyCalendarComponent.ID_PARAM }, new String[] { WeeklyCalendarComponent.CMD_EDIT, event.getCalendar().getCalendarID() + WeeklyCalendarComponent.ID_PARAM_SEPARATOR + event.getID() + WeeklyCalendarComponent.ID_PARAM_SEPARATOR + event.getBegin().getTime() }, isIframePostEnabled ? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL); inset.append("\" "); if (isIframePostEnabled) { ubu.appendTarget(inset); } inset.append(" onclick=\"return o2cl();\">"); if (hideSubject) { inset.append("<i>").append(translator.translate("cal.eventdetails.hidden")).append("</i>"); } else { inset.append(escapedSubject); } inset.append("</a>"); // append any event links if (!hideSubject) { renderEventLinks(event, inset); } // closing devent_content inset.append("</div>"); // render event tooltip content renderEventTooltip(eventWrapper, escapedSubject, hideSubject, inset, ubu, translator.getLocale()); // closing devent and devent_wrapper inset.append("</div></div>"); } // events within day iterator inset.append("</div>"); if (maxDayEventsThisDay > maxDayEvents) { maxDayEvents = maxDayEventsThisDay; } } // day irterator // do not render anything if we do not have any allday events if (maxDayEvents == 0) { return; } sb.append("\n<div id=\"o_cal_wv_daylong\" style=\"height: ").append(maxDayEvents * dayEventHeightPixels) .append("px;\">"); sb.append("<div class=\"o_cal_wv_time o_cal_wv_row0\" style=\"height: 100%;\"></div>"); sb.append(inset); sb.append("</div>"); } private void renderEvents(final int year, final int weekOfYear, final List sortedEventsWithinWeek, final StringOutput sb, final URLBuilder ubu, final Locale locale) { // render day events which are positioned absolute final Calendar cal = CalendarUtils.getStartOfWeekCalendar(year, weekOfYear, locale); Date periodStart = cal.getTime(); cal.add(Calendar.DAY_OF_YEAR, 1); Date periodEnd = cal.getTime(); // itterate over days for (int dayCounter = 0; dayCounter < days; dayCounter++) { // collect all events for actual day final List sortedEventsOfDay = new ArrayList(); for (final Iterator iter = sortedEventsWithinWeek.iterator(); iter.hasNext();) { final KalendarEventRenderWrapper eventWrapper = (KalendarEventRenderWrapper) iter.next(); final KalendarEvent nextEvent = eventWrapper.getEvent(); if (nextEvent.getEnd().before(periodStart) || nextEvent.getBegin().after(periodEnd)) { continue; } sortedEventsOfDay.add(eventWrapper); } // not that eventWrappers may get re-used if it is a multi-day event renderEventsForDay(sortedEventsOfDay, periodStart, dayCounter, sb, ubu, locale); // reposition start/end period periodStart = periodEnd; cal.add(Calendar.DAY_OF_YEAR, 1); periodEnd = cal.getTime(); } // day iteration } private void renderEventsForDay(final List sortedEvents, final Date dayStart, final int column, final StringOutput sb, final URLBuilder ubu, final Locale locale) { if (sortedEvents.isEmpty()) { return; } // this is the start of this day final long startDateLong = dayStart.getTime(); /** * STAGE 1: assign slots */ // list containing slot endpoint information (Long(lastEndPointMillis)) List slotEndPointsList = new ArrayList(); // make at least one end point slot available slotEndPointsList.add(new Long(-1)); // List of event group with equal slot widths List slotGroup = new ArrayList(); // the maximum slots for this group int maxSlotsForGroup = 1; // the latest endpoint of this group (this endpoint is part of the slotEndPointsList) long latestEndPointForGroup = -1; // Iterate over all events for (int eventCounter = 0; eventCounter < sortedEvents.size(); eventCounter++) { final KalendarEventRenderWrapper eventWrapper = (KalendarEventRenderWrapper) sortedEvents .get(eventCounter); final KalendarEvent event = eventWrapper.getEvent(); // get relative begin / end of event in millis long eventBeginRelativeMillis = event.getBegin().getTime() - startDateLong; // if begin is before our start period, correct if (eventBeginRelativeMillis < 0) { eventBeginRelativeMillis = 0; } long eventEndRelativeMillis = event.getEnd().getTime() - startDateLong; // if end relative greater than one day, correct if (eventEndRelativeMillis > (1000 * 60 * 60 * 24)) { eventEndRelativeMillis = (1000 * 60 * 60 * 24); } // first, cleanup slot group if we reach new, completely empty slot row if (eventBeginRelativeMillis > latestEndPointForGroup) { // reset slotGroup and slotEndPointsList slotGroup = new ArrayList(); slotEndPointsList = new ArrayList(); slotEndPointsList.add(new Long(-1)); maxSlotsForGroup = 1; } // search for a slot which matches relative begin and mark it in the slot list boolean foundSlot = false; int nextFreeSlot = 0; for (; nextFreeSlot < slotEndPointsList.size(); nextFreeSlot++) { final Long slotEnd = (Long) slotEndPointsList.get(nextFreeSlot); if (slotEnd.longValue() <= eventBeginRelativeMillis) { foundSlot = true; break; } } if (!foundSlot) { // no free slots, open a new slot // register end point slotEndPointsList.add(new Long(eventEndRelativeMillis)); // correct max slot width for all in slot group maxSlotsForGroup++; for (final Iterator iter = slotGroup.iterator(); iter.hasNext();) { final KalendarEventRenderWrapper rw = (KalendarEventRenderWrapper) iter.next(); rw.setMaxSlots(maxSlotsForGroup); } } else { // mark slot end point slotEndPointsList.set(nextFreeSlot, new Long(eventEndRelativeMillis)); } // add to slot group slotGroup.add(eventWrapper); // mark latest end point of slot group if (latestEndPointForGroup < eventEndRelativeMillis) { latestEndPointForGroup = eventEndRelativeMillis; } // set assigned slot eventWrapper.setAssignedSlot(nextFreeSlot); // set max slots eventWrapper.setMaxSlots(maxSlotsForGroup); // see how much we can expand to the east // note that this makes it n*(n-1) loops. Remove this to have linear times int maxExpandToEast = maxSlotsForGroup - nextFreeSlot; for (final Iterator iter = slotGroup.iterator(); iter.hasNext();) { final KalendarEventRenderWrapper rw2 = (KalendarEventRenderWrapper) iter.next(); // skip all slots which are to the west if (rw2.getAssignedSlot() <= eventWrapper.getAssignedSlot()) { continue; } // skip if we don't collide with the event if (rw2.getEvent().getEnd().before(event.getBegin())) { continue; } // now this event is limiting.... see how far we can grow to the east if (maxExpandToEast > rw2.getAssignedSlot()) { maxExpandToEast = rw2.getAssignedSlot(); } } eventWrapper.setSlotExpandToEast(maxExpandToEast); } /** * STAGE 2: calculate final geometry */ final int pixelsTotalPerPeriod = 24 * 2 * halfHourHeightPixels; final int millisTotalPerPeriod = 24 * 60 * 60 * 1000; for (int eventCounter = 0; eventCounter < sortedEvents.size(); eventCounter++) { final KalendarEventRenderWrapper eventWrapper = (KalendarEventRenderWrapper) sortedEvents .get(eventCounter); // calculate Y-coordinate and height ehich are already // total available pixels is 24 * 2 * half hour pixels // get relative begin / end of event long eventBeginRelative = eventWrapper.getEvent().getBegin().getTime() - startDateLong; if (eventBeginRelative < 0) { eventBeginRelative = 0; } long eventEndRelative = eventWrapper.getEvent().getEnd().getTime() - startDateLong; if (eventEndRelative > (1000 * 60 * 60 * 24)) { eventEndRelative = (1000 * 60 * 60 * 24); } final int yPos = (int) (pixelsTotalPerPeriod * eventBeginRelative / millisTotalPerPeriod); final int height = (int) ((eventEndRelative - eventBeginRelative) * pixelsTotalPerPeriod / millisTotalPerPeriod); // DST (daylight saving time) offset (Sommerzeit) int dstOffset = 0; if (isDstStart(eventWrapper.getEvent().getBegin())) { dstOffset = 2 * halfHourHeightPixels; } if (isDstEnd(eventWrapper.getEvent().getBegin())) { dstOffset = -2 * halfHourHeightPixels; } eventWrapper.setYPosAbsolute(yPos + dstOffset); eventWrapper.setHeightAbsolute(height); final int assignedSlot = eventWrapper.getAssignedSlot(); final int slotsExpandToEast = eventWrapper.getSlotExpandToEast(); final float slotWidth = dayRelativeWidth / eventWrapper.getMaxSlots(); eventWrapper.setXPosRelative( dayGridRelativeStart + (dayRelativeWidth * column) + (slotWidth * assignedSlot)); eventWrapper.setWidthRelative(slotWidth * slotsExpandToEast); renderSingleEvent(eventWrapper, sb, ubu, locale); } } /** * Return true when the date is the DST (daylight saving time) start date. Last Sunday in March. * * @param date * @return */ public boolean isDstStart(final Date date) { final java.util.Calendar cal = new java.util.GregorianCalendar(Calendar.getInstance().getTimeZone()); cal.setTime(date); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 30); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); cal.add(java.util.Calendar.HOUR_OF_DAY, 24); return (1 == cal.get(java.util.Calendar.HOUR_OF_DAY)); } /** * Return true when the date is the DST (daylight saving time) end date. Last Sunday in October. * * @param date * @return */ public boolean isDstEnd(final Date date) { final java.util.Calendar cal = new java.util.GregorianCalendar(Calendar.getInstance().getTimeZone()); cal.setTime(date); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 30); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); cal.add(java.util.Calendar.HOUR_OF_DAY, 24); return (23 == cal.get(java.util.Calendar.HOUR_OF_DAY)); } private void renderSingleEvent(final KalendarEventRenderWrapper eventWrapper, final StringOutput sb, final URLBuilder ubu, final Locale locale) { final KalendarEvent event = eventWrapper.getEvent(); final boolean hideSubject = eventWrapper.getCalendarAccess() == KalendarRenderWrapper.ACCESS_READ_ONLY && !eventWrapper.getKalendarRenderWrapper().isImported() && event.getClassification() != KalendarEvent.CLASS_PUBLIC; String escapedSubject = Formatter.escWithBR(event.getSubject()).toString(); escapedSubject = escapedSubject.replace('\r', ' '); sb.append("\n<div class=\"o_cal_wv_event_wrapper\" style=\""); sb.append("left: ").append("" + eventWrapper.getXPosRelative()); sb.append("%; width: ").append("" + eventWrapper.getWidthRelative()); sb.append("%; top: ").append(eventWrapper.getYPosAbsolute() - 1); // fixt start position -1px for top border sb.append("px; height: ").append(eventWrapper.getHeightAbsolute() - 1); // fix height -1 px for bottom border sb.append("px;\""); sb.append(">"); sb.append("<div class=\"o_cal_wv_event ").append(eventWrapper.getCssClass()).append("\" style=\""); sb.append("width: auto; height: 100%\">"); sb.append("<div class=\"o_cal_wv_event_header\">"); if (eventWrapper.getCalendarAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) { sb.append("<a href=\""); ubu.buildURI(sb, new String[] { WeeklyCalendarComponent.ID_CMD, WeeklyCalendarComponent.ID_PARAM }, new String[] { WeeklyCalendarComponent.CMD_EDIT, event.getCalendar().getCalendarID() + WeeklyCalendarComponent.ID_PARAM_SEPARATOR + event.getID() + WeeklyCalendarComponent.ID_PARAM_SEPARATOR + event.getBegin().getTime() }, isIframePostEnabled ? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL); sb.append("\" "); if (isIframePostEnabled) { ubu.appendTarget(sb); } sb.append(" onclick=\"return o2cl();\">"); } sb.append(CalendarUtils.getTimeAsString(event.getBegin(), locale)); if (eventWrapper.getCalendarAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) { sb.append("</a>"); } sb.append("</div>"); sb.append("<div class=\"o_cal_wv_event_content\">"); // check if we need to hide textual information. // Private events on readonly kalendars are already filtered out and do not appear in the render list. // We thus only need to check for freebusy events in readonly calendars. if (!hideSubject) { sb.append(escapedSubject); // append any event links renderEventLinks(event, sb); } sb.append("</div>"); // tooltip content renderEventTooltip(eventWrapper, escapedSubject, hideSubject, sb, ubu, locale); sb.append("</div></div>"); } private void renderEventTooltip(final KalendarEventRenderWrapper eventWrapper, final String escapedSubject, final boolean hideSubject, final StringOutput sb, final URLBuilder ubu, final Locale locale) { final KalendarEvent event = eventWrapper.getEvent(); // Tooltip content sb.append("<div class=\"o_cal_wv_event_tooltip"); if (event.isAllDayEvent()) { // add marker css class used in js code to identify all day events sb.append(" o_cal_allday"); } sb.append("\">"); // time sb.append("<div class=\"o_cal_time\">\n"); final Translator translator = Util.createPackageTranslator(CalendarManager.class, locale); final Calendar cal = CalendarUtils.createCalendarInstance(locale); final Date begin = event.getBegin(); final Date end = event.getEnd(); cal.setTime(begin); sb.append(StringHelper.formatLocaleDateFull(begin.getTime(), locale)); if (!event.isAllDayEvent()) { sb.append("<br />").append(StringHelper.formatLocaleTime(begin.getTime(), locale)); sb.append(" - "); if (!DateUtils.isSameDay(begin, end)) { sb.append(StringHelper.formatLocaleDateFull(end.getTime(), locale)).append(", "); } sb.append(StringHelper.formatLocaleTime(end.getTime(), locale)); } sb.append("</div>\n"); if (!hideSubject) { sb.append("<div class=\"o_cal_wv_event_tooltip_content\">"); sb.append(escapedSubject); } // location if (StringHelper.containsNonWhitespace(event.getLocation())) { sb.append("<div class=\"o_cal_location\">\n"); if (!hideSubject) { sb.append("<b>").append(translator.translate("cal.form.location")).append("</b>:"); sb.append(event.getLocation()); } sb.append("</div>\n"); } // links if (!hideSubject) { renderEventLinks(event, sb); } if (eventWrapper.getCalendarAccess() == KalendarRenderWrapper.ACCESS_READ_WRITE) { // edit link sb.append("<div class=\"o_cal_tooltip_buttons\"><a class=\"b_button b_xsmall\" href=\""); ubu.buildURI(sb, new String[] { WeeklyCalendarComponent.ID_CMD, WeeklyCalendarComponent.ID_PARAM }, new String[] { WeeklyCalendarComponent.CMD_EDIT, event.getCalendar().getCalendarID() + WeeklyCalendarComponent.ID_PARAM_SEPARATOR + event.getID() + WeeklyCalendarComponent.ID_PARAM_SEPARATOR + event.getBegin().getTime() }, isIframePostEnabled ? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL); sb.append("\" "); if (isIframePostEnabled) { ubu.appendTarget(sb); } sb.append("><span>"); sb.append(translator.translate("edit")); sb.append("</span></a></div>"); } // tooltip_content if (!hideSubject) { sb.append("</div>"); } // event_tooltip sb.append("</div>"); } private void renderEventLinks(final KalendarEvent event, final StringOutput sb) { final List kalendarEventLinks = event.getKalendarEventLinks(); if (kalendarEventLinks != null) { sb.append("<div class=\"o_cal_links\">"); for (final Iterator iter = kalendarEventLinks.iterator(); iter.hasNext();) { final KalendarEventLink link = (KalendarEventLink) iter.next(); sb.append("<br /><b>"); sb.append("<a href=\"javascript:top.o_openUriInMainWindow('").append(link.getURI()) .append("')\" title=\"").append(StringEscapeUtils.escapeHtml(link.getDisplayName())) .append("\" "); final String iconCssClass = link.getIconCssClass(); if (StringHelper.containsNonWhitespace(iconCssClass)) { sb.append("class=\"b_with_small_icon_left ").append(iconCssClass).append("\""); } sb.append(" onclick=\"return o2cl();\">").append(link.getDisplayName()).append("</a>"); sb.append("</b>"); } sb.append("</div>"); } } private void renderWeekHeader(final int year, final int weekOfYear, final boolean enableAddEvent, final StringOutput sb, final URLBuilder ubu, final Locale locale) { final Calendar cal = CalendarUtils.getStartOfWeekCalendar(year, weekOfYear, locale); final Calendar calNow = CalendarUtils.createCalendarInstance(locale); cal.set(Calendar.HOUR_OF_DAY, calNow.get(Calendar.HOUR_OF_DAY)); cal.set(Calendar.MINUTE, calNow.get(Calendar.MINUTE)); final SimpleDateFormat dayMonth = new SimpleDateFormat("E dd.MM", locale); // render header sb.append("\n<div id=\"o_cal_wv_header\">"); sb.append("<div class=\"o_cal_wv_time o_cal_wv_row0\">"); sb.append("<div class=\"o_cal_wv_legend_hours\"><div></div></div></div>"); int dayToday = -1; if ((calNow.get(Calendar.WEEK_OF_YEAR) == weekOfYear) && (calNow.get(Calendar.YEAR) == year)) { // if we are within current week, adjust dayToday dayToday = calNow.get(Calendar.DAY_OF_WEEK); } for (int i = 1; i <= days; i++) { final int dayOfWeekIter = cal.get(Calendar.DAY_OF_WEEK); sb.append("\n<div class=\"o_cal_wv_day "); sb.append("o_cal_wv_row"); sb.append(i); sb.append(" "); if (i == 7) { // terminate last day sb.append("o_cal_wv_lastday "); } if (dayOfWeekIter == dayToday) { // current day sb.append("o_cal_wv_today "); } else if (dayOfWeekIter == Calendar.SATURDAY || dayOfWeekIter == Calendar.SUNDAY) { // holiday sb.append("o_cal_wv_holiday "); } sb.append("\">"); sb.append("<div class=\"o_cal_wv_legend_day\"><div>"); if (enableAddEvent) { sb.append("<a href=\""); ubu.buildURI(sb, new String[] { WeeklyCalendarComponent.ID_CMD, WeeklyCalendarComponent.ID_PARAM }, new String[] { WeeklyCalendarComponent.CMD_ADD_ALLDAY, dmyDateFormat.format(cal.getTime()) }, isIframePostEnabled ? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL); sb.append("\" "); if (isIframePostEnabled) { ubu.appendTarget(sb); } sb.append(" onclick=\"return o2cl();\">"); sb.append(dayMonth.format(cal.getTime())); sb.append("</a>"); } else { sb.append(dayMonth.format(cal.getTime())); } sb.append("</div></div></div>"); // add one day to calendar cal.add(Calendar.DAY_OF_YEAR, 1); } sb.append("</div>"); } private void renderWeekGrid(final int year, final int weekOfYear, final boolean enableAddEvent, final StringOutput sb, final URLBuilder ubu, final Locale locale) { final Calendar cal = CalendarUtils.getStartOfWeekCalendar(year, weekOfYear, locale); int dayToday = -1; final Calendar calNow = CalendarUtils.createCalendarInstance(locale); if ((calNow.get(Calendar.WEEK_OF_YEAR) == weekOfYear) && (calNow.get(Calendar.YEAR) == year)) { // if we are within current week, adjust dayToday dayToday = calNow.get(Calendar.DAY_OF_WEEK); } // render day grid sb.append("\n<div class=\"o_cal_wv_time o_cal_wv_row0\">"); for (int i = 0; i < 23; i++) { sb.append("<div class=\"o_cal_wv_legend_hour\"><div>"); sb.append(i); sb.append(":00</div></div>"); } sb.append("<div class=\"o_cal_wv_legend_hour o_cal_wv_lasthour\"><div>23:00</div></div></div>"); // render daily grid // reposition calendar to start of week for (int i = 1; i <= 7; i++) { final int dayOfWeekIter = cal.get(Calendar.DAY_OF_WEEK); sb.append("\n<div class=\"o_cal_wv_day o_cal_wv_row"); sb.append(i); if (dayOfWeekIter == dayToday) { // current day sb.append(" o_cal_wv_today"); } else if (dayOfWeekIter == Calendar.SATURDAY || dayOfWeekIter == Calendar.SUNDAY) { // holiday sb.append(" o_cal_wv_holiday"); } sb.append("\">"); for (int j = 0; j < 23; j++) { // set calendar add link to corresponding hour cal.set(Calendar.HOUR_OF_DAY, j); // build the add event uri final StringOutput uri = new StringOutput(); ubu.buildJavaScriptBgCommand(uri, new String[] { WeeklyCalendarComponent.ID_CMD, WeeklyCalendarComponent.ID_PARAM }, new String[] { WeeklyCalendarComponent.CMD_ADD, dmyDateFormat.format(cal.getTime()) }, isIframePostEnabled ? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL, true); sb.append("<div class=\"o_cal_wv_hour\""); if (enableAddEvent) { sb.append(" onclick=\""); sb.append(uri); } sb.append("\"></div>"); sb.append("<div class=\"o_cal_wv_half_hour\""); if (enableAddEvent) { sb.append(" onclick=\""); sb.append(uri); } sb.append("\"></div>"); } // set calendar add link to last hour (23) cal.set(Calendar.HOUR_OF_DAY, 23); final StringOutput uri = new StringOutput(); ubu.buildJavaScriptBgCommand(uri, new String[] { WeeklyCalendarComponent.ID_CMD, WeeklyCalendarComponent.ID_PARAM }, new String[] { WeeklyCalendarComponent.CMD_ADD, dmyDateFormat.format(cal.getTime()) }, isIframePostEnabled ? AJAXFlags.MODE_TOBGIFRAME : AJAXFlags.MODE_NORMAL, true); sb.append("<div class=\"o_cal_wv_hour\""); if (enableAddEvent) { sb.append(" onclick=\""); sb.append(uri); } sb.append("\"></div>"); sb.append("<div class=\"o_cal_wv_half_hour o_cal_wv_lasthour\""); if (enableAddEvent) { sb.append(" onclick=\""); sb.append(uri); } sb.append("\"></div></div>"); cal.add(Calendar.DAY_OF_YEAR, 1); } } /** * @see org.olat.core.gui.components.ComponentRenderer#renderHeaderIncludes(org.olat.core.gui.render.Renderer, org.olat.core.gui.render.StringOutput, * org.olat.core.gui.components.Component, org.olat.core.gui.render.URLBuilder, org.olat.core.gui.translator.Translator, org.olat.core.gui.render.RenderingState) */ public void renderHeaderIncludes(final Renderer renderer, final StringOutput sb, final Component source, final URLBuilder ubu, final Translator translator, final RenderingState rstate) { // nothing to include, css and javascript is included by calender component } /** * @see org.olat.core.gui.components.ComponentRenderer#renderBodyOnLoadJSFunctionCall(org.olat.core.gui.render.Renderer, org.olat.core.gui.render.StringOutput, * org.olat.core.gui.components.Component, org.olat.core.gui.render.RenderingState) */ public void renderBodyOnLoadJSFunctionCall(final Renderer renderer, final StringOutput sb, final Component source, final RenderingState rstate) { // using Ext.onReady() instead } }