You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mm...@apache.org on 2005/07/13 17:33:25 UTC
svn commit: r216175 [3/4] - in /myfaces: build/trunk/
examples/trunk/sandbox/ examples/trunk/sandbox/WEB-INF/
examples/trunk/sandbox/src/java/org/apache/myfaces/examples/schedule/
sandbox/trunk/conf/ sandbox/trunk/src/java/org/apache/myfaces/custom/sch...
Added: myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/PlannerRenderer.java
URL: http://svn.apache.org/viewcvs/myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/PlannerRenderer.java?rev=216175&view=auto
==============================================================================
--- myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/PlannerRenderer.java (added)
+++ myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/PlannerRenderer.java Wed Jul 13 08:33:22 2005
@@ -0,0 +1,955 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.myfaces.custom.schedule.renderer;
+
+
+import java.io.IOException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIForm;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+import javax.faces.render.Renderer;
+
+import org.apache.myfaces.component.html.util.AddResource;
+import org.apache.myfaces.custom.schedule.HtmlPlanner;
+import org.apache.myfaces.custom.schedule.HtmlSchedule;
+import org.apache.myfaces.custom.schedule.model.Day;
+import org.apache.myfaces.custom.schedule.model.PlannerEntity;
+import org.apache.myfaces.custom.schedule.model.ScheduleEntry;
+import org.apache.myfaces.custom.schedule.util.ScheduleEntryComparator;
+import org.apache.myfaces.renderkit.html.HTML;
+
+
+/**
+ * <p>
+ * Renderer for the UIPlanner component
+ * </p>
+ *
+ * @author Jurgen Lust (latest modification by $Author$)
+ * @author Bruno Aranda (adaptation of Jurgen's code to myfaces)
+ * @version $Revision$
+ */
+public class PlannerRenderer
+ extends Renderer
+{
+ //~ Static fields/initializers ---------------------------------------------
+
+ private static final ScheduleEntryComparator comparator =
+ new ScheduleEntryComparator();
+
+ //~ Instance fields --------------------------------------------------------
+
+ private final int ROW_HEIGHT_IN_PIXELS = 22;
+
+ //~ Methods ----------------------------------------------------------------
+
+ /**
+ * @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeBegin(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ if (!component.isRendered()) {
+ return;
+ }
+
+ AddResource.addStyleSheet(HtmlSchedule.class, "css/schedule.css", context);
+
+ HtmlPlanner planner = (HtmlPlanner) component;
+ Map attributes = planner.getAttributes();
+ ResponseWriter writer = context.getResponseWriter();
+
+ int numberOfRows = planner.getModel().numberOfEntities();
+
+ int gridHeight = (numberOfRows * 22) + 3 + 47;
+
+ writer.startElement(HTML.DIV_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "planner", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: " + String.valueOf(gridHeight) + "px; overflow: hidden;",
+ null
+ );
+ writeBackground(context, planner, writer);
+ writeForegroundStart(context, planner, writer);
+ }
+
+ /**
+ * @see javax.faces.render.Renderer#encodeChildren(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeChildren(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ if (!component.isRendered()) {
+ return;
+ }
+
+ HtmlPlanner planner = (HtmlPlanner) component;
+ Map attributes = planner.getAttributes();
+ ResponseWriter writer = context.getResponseWriter();
+
+ for (
+ Iterator entityIterator = planner.getModel().entityIterator();
+ entityIterator.hasNext();
+ ) {
+ PlannerEntity entity = (PlannerEntity) entityIterator.next();
+ writer.startElement(HTML.TR_ELEM, planner);
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "gutter", null);
+ writer.startElement(HTML.DIV_ELEM, planner);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: 1px; width: " +
+ String.valueOf(getGutterWidth(planner.getAttributes())) + "px",
+ null
+ );
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+
+ int numberOfDays = planner.getModel().numberOfDays();
+ float columnWidth =
+ (numberOfDays == 0) ? 100f : (100 / numberOfDays);
+
+ for (
+ Iterator dayIterator = planner.getModel().dayIterator();
+ dayIterator.hasNext();
+ ) {
+ Day day = (Day) dayIterator.next();
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "row", null);
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(columnWidth) + "%", null
+ );
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: 21px; border-left-style: solid; border-left-width: 1px; border-top-style: none; border-right-style: none; border-bottom-style: none;",
+ null
+ );
+ writer.startElement(HTML.DIV_ELEM, null);
+ writer.writeAttribute(HTML.CLASS_ATTR, "row", null);
+ writer.writeAttribute(
+ HTML.STYLE_CLASS_ATTR,
+ "position: relative; top: 0px; left: 0px; width: 100%; height: 100%; padding: 0px; z-index: 0; vertical-align: middle;",
+ null
+ );
+ writeEntries(context, planner, entity, day, writer);
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+ }
+ }
+
+ /**
+ * @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeEnd(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ if (!component.isRendered()) {
+ return;
+ }
+
+ HtmlPlanner planner = (HtmlPlanner) component;
+ Map attributes = planner.getAttributes();
+ ResponseWriter writer = context.getResponseWriter();
+ writeForegroundEnd(context, planner, writer);
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ /**
+ * <p>
+ * Determine the width of the left gutter
+ * </p>
+ *
+ * @param attributes the attributes
+ *
+ * @return the gutter width in pixels
+ */
+ protected int getGutterWidth(Map attributes)
+ {
+ try {
+ Integer width =
+ Integer.valueOf((String) attributes.get("gutterWidthInPixels"));
+
+ return width.intValue();
+ } catch (NumberFormatException nfe) {
+ return 200;
+ }
+ }
+
+ /**
+ * <p>
+ * The date format that is used in the planner header
+ * </p>
+ *
+ * @param attributes the attributes
+ *
+ * @return Returns the headerDateFormat.
+ */
+ protected String getHeaderDateFormat(Map attributes)
+ {
+ return (String) attributes.get("headerDateFormat");
+ }
+
+ /**
+ * <p>
+ * Get the parent form of the planner component
+ * </p>
+ *
+ * @param component the component
+ *
+ * @return the parent form
+ */
+ protected UIForm getParentForm(UIComponent component)
+ {
+ UIComponent parent = component.getParent();
+
+ while (parent != null) {
+ if (parent instanceof UIForm) {
+ break;
+ }
+
+ parent = parent.getParent();
+ }
+
+ return (UIForm) parent;
+ }
+
+ /**
+ * <p>
+ * Should the legend be rendered?
+ * </p>
+ *
+ * TODO the rendering of the legend has not been implemented yet
+ *
+ * @param attributes the attributes
+ *
+ * @return whether to render the legend
+ */
+ protected boolean showLegend(Map attributes)
+ {
+ return Boolean.valueOf((String) attributes.get("legend")).booleanValue();
+ }
+
+ /**
+ * <p>
+ * Should the tooltip be rendered?
+ * </p>
+ *
+ * @param attributes the attributes
+ *
+ * @return whether or not tooltips should be rendered
+ */
+ protected boolean showTooltip(Map attributes)
+ {
+ return Boolean.valueOf((String) attributes.get("tooltip")).booleanValue();
+ }
+
+ private String getCellClass(
+ HtmlPlanner planner,
+ Day day,
+ int hour
+ )
+ {
+ if (!day.isWorkingDay()) {
+ return "free";
+ }
+
+ if (
+ (hour >= planner.getWorkingStartHour()) &&
+ (hour < planner.getWorkingEndHour())
+ ) {
+ return ((hour % 2) == 0) ? "even" : "uneven";
+ }
+
+ return "free";
+ }
+
+ private String getDateString(
+ FacesContext context,
+ Map attributes,
+ Date date
+ )
+ {
+ DateFormat format;
+ String pattern = getHeaderDateFormat(attributes);
+
+ if ((pattern != null) && (pattern.length() > 0)) {
+ format = new SimpleDateFormat(pattern);
+ } else {
+ if (context.getApplication().getDefaultLocale() != null) {
+ format =
+ DateFormat.getDateInstance(
+ DateFormat.MEDIUM,
+ context.getApplication().getDefaultLocale()
+ );
+ } else {
+ format = DateFormat.getDateInstance(DateFormat.MEDIUM);
+ }
+ }
+
+ return format.format(date);
+ }
+
+ private String getTooltipText(
+ ScheduleEntry entry,
+ Map attributes
+ )
+ {
+ if (!showTooltip(attributes)) {
+ return null;
+ }
+
+ //TODO enable tooltips again
+ return "";
+
+ /*
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(
+ "return makeTrue(domTT_activate(this, event, 'caption', '"
+ );
+
+ if (entry.getTitle() != null) {
+ buffer.append(escape(entry.getTitle()));
+ }
+
+ buffer.append("', 'content', '<i>");
+
+ if (entry.getSubtitle() != null) {
+ buffer.append(escape(entry.getSubtitle()));
+ }
+
+ buffer.append("</i>");
+
+ if (entry.getDescription() != null) {
+ buffer.append("<br/>");
+ buffer.append(escape(entry.getDescription()));
+ }
+
+ buffer.append("', 'trail', true));");
+
+ return buffer.toString();
+ */
+ }
+
+ private boolean containsEntry(
+ HtmlPlanner planner,
+ Day day,
+ ScheduleEntry entry
+ )
+ {
+ if ((day == null) || (entry == null)) {
+ return false;
+ }
+
+ Calendar cal = GregorianCalendar.getInstance();
+ cal.setTime(day.getDate());
+ cal.set(Calendar.HOUR_OF_DAY, planner.getVisibleStartHour());
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+
+ Date dayStart = cal.getTime();
+ cal.set(Calendar.HOUR_OF_DAY, planner.getVisibleEndHour());
+
+ Date dayEnd = cal.getTime();
+
+ return entry.getEndTime().after(dayStart) &&
+ entry.getStartTime().before(dayEnd);
+ }
+
+ private String escape(String text)
+ {
+ if (text == null) {
+ return null;
+ }
+
+ return text.replaceAll("'", """);
+ }
+
+ /**
+ * <p>
+ * Draw the planner background, i.e. the grid
+ * </p>
+ *
+ * @param context the FacesContext
+ * @param planner the Planner component
+ * @param writer the ResponseWriter
+ *
+ * @throws IOException when the background cannot be drawn
+ * @throws NullPointerException
+ */
+ private void writeBackground(
+ FacesContext context,
+ HtmlPlanner planner,
+ ResponseWriter writer
+ )
+ throws IOException
+ {
+ //a planner component should always be inside a UIForm
+ UIForm parentForm = getParentForm(planner);
+
+ if (parentForm == null) {
+ throw new NullPointerException("No parent UIForm found");
+ }
+
+ writer.startElement(HTML.DIV_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "background", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; z-index: 0;",
+ null
+ );
+
+ //background table for the schedule grid
+ writer.startElement(HTML.TABLE_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "background", null);
+ writer.writeAttribute(HTML.CELLPADDING_ATTR, "0", null);
+ writer.writeAttribute(HTML.CELLSPACING_ATTR, "1", null);
+ writer.writeAttribute(HTML.STYLE_ATTR, "width: 100%; height: 100%;", null);
+ writer.startElement(HTML.TBODY_ELEM, planner);
+
+ //header row, containing the day names
+ writer.startElement(HTML.TR_ELEM, planner);
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "gutter", null);
+ writer.writeAttribute("rowspan", "2", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "padding: 0px; vertical-align: middle; height: 21px; border-style: none; border-width: 0px; overflow: hidden; whitespace: nowrap;",
+ null
+ );
+ writer.startElement(HTML.DIV_ELEM, planner);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: 1px; width: " +
+ String.valueOf(getGutterWidth(planner.getAttributes())) + "px", null
+ );
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+
+ int numberOfDays = planner.getModel().numberOfDays();
+ float columnWidth = (numberOfDays == 0) ? 100f : (100 / numberOfDays);
+
+ for (
+ Iterator dayIterator = planner.getModel().dayIterator();
+ dayIterator.hasNext();
+ ) {
+ Day day = (Day) dayIterator.next();
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "header", null);
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(columnWidth) + "%", null
+ );
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "overflow: hidden; height: 31px;", null
+ );
+ writer.startElement(HTML.DIV_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "header", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: relative; left: 0px; top: 0px; width: 100%; height: 100%;",
+ null
+ );
+ writer.startElement(HTML.SPAN_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "date", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: absolute; left: 0px; top: 0px; width: 100%; height: 15px; overflow: hidden; white-space: nowrap;",
+ null
+ );
+ writer.writeText(
+ getDateString(context, planner.getAttributes(), day.getDate()),
+ null
+ );
+ writer.endElement(HTML.SPAN_ELEM);
+
+ //write the name of the holiday, if there is one
+ if (
+ (day.getSpecialDayName() != null) &&
+ (day.getSpecialDayName().length() > 0)
+ ) {
+ writer.startElement(HTML.SPAN_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "holiday", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: absolute; left: 0px; top: 15px; width: 100%; overflow: hidden; white-space: nowrap;",
+ null
+ );
+ writer.writeText(day.getSpecialDayName(), null);
+ writer.endElement(HTML.SPAN_ELEM);
+ }
+
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+
+ //second header row, containing the hours
+ writer.startElement(HTML.TR_ELEM, planner);
+
+ int numberOfHours =
+ planner.getVisibleEndHour() - planner.getVisibleStartHour();
+ float hourWidth = (numberOfHours <= 0) ? 100f : (100 / numberOfHours);
+
+ for (
+ Iterator dayIterator = planner.getModel().dayIterator();
+ dayIterator.hasNext();
+ ) {
+ Day day = (Day) dayIterator.next();
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(columnWidth) + "%", null
+ );
+ writer.startElement(HTML.TABLE_ELEM, planner);
+ writer.writeAttribute(HTML.STYLE_ATTR, "height: 100%; width: 100%", null);
+ writer.writeAttribute(HTML.CELLPADDING_ATTR, "0", null);
+ writer.writeAttribute(HTML.CELLSPACING_ATTR, "0", null);
+ writer.writeAttribute("border", "0", null);
+ writer.startElement(HTML.TR_ELEM, planner);
+
+ for (
+ int hcol = planner.getVisibleStartHour();
+ hcol < planner.getVisibleEndHour(); hcol++
+ ) {
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "hours", null);
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(hourWidth) + "%", null
+ );
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "overflow: hidden; height: 15px; border-left-style: solid; border-left-width: 1px; border-top-style: none; border-right-style: none; border-bottom-style: none;",
+ null
+ );
+ writer.startElement(HTML.DIV_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "header", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: relative; left: 0px; top: 0px; width: 100%; height: 100%;",
+ null
+ );
+ writer.startElement(HTML.SPAN_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "hours", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; overflow: hidden; white-space: nowrap;",
+ null
+ );
+ writer.writeText(String.valueOf(hcol) + ":00", null);
+ writer.endElement(HTML.SPAN_ELEM);
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+ writer.endElement(HTML.TABLE_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+
+ //the actual entity rows start here
+ for (
+ Iterator entityIterator = planner.getModel().entityIterator();
+ entityIterator.hasNext();
+ ) {
+ PlannerEntity entity = (PlannerEntity) entityIterator.next();
+ writer.startElement(HTML.TR_ELEM, planner);
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "gutter", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "padding: 0px; vertical-align: middle; height: 21px; border-style: none; border-width: 0px; overflow: hidden; whitespace: nowrap;",
+ null
+ );
+ writer.startElement(HTML.SPAN_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "title", null);
+ writer.writeAttribute(HTML.STYLE_ATTR, "height: 100%;", null);
+ writer.writeText(entity.getName(), null);
+ writer.endElement(HTML.SPAN_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+
+ for (
+ Iterator dayIterator = planner.getModel().dayIterator();
+ dayIterator.hasNext();
+ ) {
+ Day day = (Day) dayIterator.next();
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(columnWidth) + "%", null
+ );
+ writer.startElement(HTML.TABLE_ELEM, planner);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "height: 100%; width: 100%", null
+ );
+ writer.writeAttribute(HTML.CELLPADDING_ATTR, "0", null);
+ writer.writeAttribute(HTML.CELLSPACING_ATTR, "0", null);
+ writer.writeAttribute("border", "0", null);
+ writer.startElement(HTML.TR_ELEM, planner);
+
+ for (
+ int hcol = planner.getVisibleStartHour();
+ hcol < planner.getVisibleEndHour(); hcol++
+ ) {
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(
+ HTML.CLASS_ATTR, getCellClass(planner, day, hcol), null
+ );
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(hourWidth) + "%", null
+ );
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: 21px; overflow: hidden; border-left-style: solid; border-left-width: 1px; border-top-style: none; border-right-style: none; border-bottom-style: none;",
+ null
+ );
+ writer.write(HTML.NBSP_ENTITY);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+ writer.endElement(HTML.TABLE_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+ }
+
+ writer.endElement(HTML.TBODY_ELEM);
+ writer.endElement(HTML.TABLE_ELEM);
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ /**
+ * <p>
+ * Draw the entries on the planner
+ * </p>
+ *
+ * @param context the FacesContext
+ * @param planner the Planner component
+ * @param entity the planner entity
+ * @param day the day
+ * @param writer the responsewriter
+ *
+ * @throws IOException when the entries cannot be drawn
+ */
+ private void writeEntries(
+ FacesContext context,
+ HtmlPlanner planner,
+ PlannerEntity entity,
+ Day day,
+ ResponseWriter writer
+ )
+ throws IOException
+ {
+ for (Iterator entryIterator = entity.iterator();
+ entryIterator.hasNext();
+ ) {
+ ScheduleEntry entry = (ScheduleEntry) entryIterator.next();
+
+ if (containsEntry(planner, day, entry)) {
+ EntryWrapper wrapper = new EntryWrapper(entry, day, entity);
+ writer.startElement(HTML.DIV_ELEM, planner);
+
+ //draw the tooltip
+ if (showTooltip(planner.getAttributes())) {
+ writer.writeAttribute(
+ "onmouseover",
+ getTooltipText(wrapper.entry, planner.getAttributes()),
+ null
+ );
+ }
+
+ writer.writeAttribute(HTML.CLASS_ATTR, "entry", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, wrapper.getBounds(planner), null
+ );
+ writer.endElement(HTML.DIV_ELEM);
+ }
+ }
+ }
+
+ private void writeForegroundEnd(
+ FacesContext context,
+ HtmlPlanner planner,
+ ResponseWriter writer
+ )
+ throws IOException
+ {
+ writer.endElement(HTML.TBODY_ELEM);
+ writer.endElement(HTML.TABLE_ELEM);
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ private void writeForegroundStart(
+ FacesContext context,
+ HtmlPlanner planner,
+ ResponseWriter writer
+ )
+ throws IOException
+ {
+ writer.startElement(HTML.DIV_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "foreground", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; z-index: 1;",
+ null
+ );
+
+ //foreground table for the planner grid
+ writer.startElement(HTML.TABLE_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "foreground", null);
+ writer.writeAttribute(HTML.CELLPADDING_ATTR, "0", null);
+ writer.writeAttribute(HTML.CELLSPACING_ATTR, "1", null);
+ writer.writeAttribute(HTML.STYLE_ATTR, "width: 100%; height: 100%;", null);
+ writer.startElement(HTML.TBODY_ELEM, planner);
+
+ //header row containing the day names
+ writer.startElement(HTML.TR_ELEM, planner);
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "gutter", null);
+ writer.writeAttribute("rowspan", "2", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "padding: 0px; vertical-align: middle; height: 21px; border-style: none; border-width: 0px; overflow: hidden; whitespace: nowrap;",
+ null
+ );
+ writer.startElement(HTML.DIV_ELEM, planner);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: 1px; width: " +
+ String.valueOf(getGutterWidth(planner.getAttributes())) + "px", null
+ );
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+
+ int numberOfDays = planner.getModel().numberOfDays();
+ float columnWidth = (numberOfDays == 0) ? 100f : (100 / numberOfDays);
+
+ for (
+ Iterator dayIterator = planner.getModel().dayIterator();
+ dayIterator.hasNext();
+ ) {
+ Day day = (Day) dayIterator.next();
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "header", null);
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(columnWidth) + "%", null
+ );
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "overflow: hidden; height: 31px;", null
+ );
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+
+ //header row containing the hours
+ writer.startElement(HTML.TR_ELEM, planner);
+
+ for (
+ Iterator dayIterator = planner.getModel().dayIterator();
+ dayIterator.hasNext();
+ ) {
+ Day day = (Day) dayIterator.next();
+ writer.startElement(HTML.TD_ELEM, planner);
+ writer.writeAttribute(HTML.CLASS_ATTR, "hours", null);
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(columnWidth) + "%", null
+ );
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "overflow: hidden; height: 15px; border-style: none; border-width: 0px",
+ null
+ );
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+ }
+
+ //~ Inner Classes ----------------------------------------------------------
+
+ /**
+ *
+ */
+ private class EntryWrapper
+ implements Comparable
+ {
+ //~ Static fields/initializers -----------------------------------------
+
+ private static final int HOUR = 1000 * 3600;
+
+ //~ Instance fields ----------------------------------------------------
+
+ private final Day day;
+ private final PlannerEntity entity;
+ private final ScheduleEntry entry;
+
+ //~ Constructors -------------------------------------------------------
+
+ EntryWrapper(
+ ScheduleEntry entry,
+ Day day,
+ PlannerEntity entity
+ )
+ {
+ this.entry = entry;
+ this.day = day;
+ this.entity = entity;
+ }
+
+ //~ Methods ------------------------------------------------------------
+
+ /**
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(Object o)
+ {
+ return comparator.compare(entry, o);
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object o)
+ {
+ if (o instanceof EntryWrapper) {
+ EntryWrapper other = (EntryWrapper) o;
+
+ boolean returnboolean =
+ (entry.getStartTime().equals(other.entry.getStartTime())) &&
+ (entry.getEndTime().equals(other.entry.getEndTime())) &&
+ (entry.getId().equals(other.entry.getId())) &&
+ (day.equals(other.day));
+ /*
+ new EqualsBuilder().append(
+ entry.getStartTime(), other.entry.getStartTime()
+ ).append(entry.getEndTime(), other.entry.getEndTime())
+ .append(
+ entry.getId(), other.entry.getId()
+ ).append(day, other.day).isEquals();*/
+
+ return returnboolean;
+ }
+
+ return false;
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode()
+ {
+ int returnint = entry.getStartTime().hashCode() ^
+ entry.getEndTime().hashCode() ^
+ entry.getId().hashCode();
+
+ return returnint;
+ }
+
+ /**
+ * <p>
+ * Determine the bounds of the entry
+ * </p>
+ *
+ * @param planner the planner component
+ *
+ * @return the bounds, as CSS position attributes
+ */
+ String getBounds(HtmlPlanner planner)
+ {
+ Calendar cal = GregorianCalendar.getInstance();
+ cal.setTime(day.getDate());
+
+ int curyear = cal.get(Calendar.YEAR);
+ int curmonth = cal.get(Calendar.MONTH);
+ int curday = cal.get(Calendar.DATE);
+
+ cal.setTime(entry.getStartTime());
+ cal.set(curyear, curmonth, curday);
+
+ long startMillis = cal.getTimeInMillis();
+ cal.set(Calendar.HOUR_OF_DAY, planner.getVisibleStartHour());
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+
+ long visibleStartMillis = cal.getTimeInMillis();
+ startMillis =
+ day.equalsDate(entry.getStartTime())
+ ? Math.max(startMillis, visibleStartMillis) : visibleStartMillis;
+ cal.setTime(entry.getEndTime());
+ cal.set(curyear, curmonth, curday);
+
+ long endMillis = cal.getTimeInMillis();
+ cal.set(Calendar.HOUR_OF_DAY, planner.getVisibleEndHour());
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+
+ long visibleEndMillis = cal.getTimeInMillis();
+ endMillis =
+ day.equalsDate(entry.getEndTime())
+ ? Math.min(endMillis, visibleEndMillis) : visibleEndMillis;
+
+ float left =
+ (float) ((startMillis - visibleStartMillis) * 100) / (float) (visibleEndMillis -
+ visibleStartMillis);
+ float width =
+ (float) ((endMillis - startMillis) * 100) / (float) (visibleEndMillis -
+ visibleStartMillis);
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(
+ "position: absolute; padding: 0px; top: 0px; height: 21px; left: "
+ );
+ buffer.append(String.valueOf(left));
+ buffer.append("%; width: ");
+ buffer.append(String.valueOf(width));
+ buffer.append(
+ "%; overflow: hidden; border-style-none; border-width: 0px;"
+ );
+
+ return buffer.toString();
+ }
+ }
+}
+//The End
Added: myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleCompactMonthRenderer.java
URL: http://svn.apache.org/viewcvs/myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleCompactMonthRenderer.java?rev=216175&view=auto
==============================================================================
--- myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleCompactMonthRenderer.java (added)
+++ myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleCompactMonthRenderer.java Wed Jul 13 08:33:22 2005
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.myfaces.custom.schedule.renderer;
+
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeSet;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import org.apache.myfaces.custom.schedule.HtmlSchedule;
+import org.apache.myfaces.custom.schedule.model.ScheduleDay;
+import org.apache.myfaces.renderkit.html.HTML;
+
+
+/**
+ * <p>
+ * Renderer for the month view of the Schedule component
+ * </p>
+ *
+ * @author Jurgen Lust (latest modification by $Author$)
+ * @author Bruno Aranda (adaptation of Jurgen's code to myfaces)
+ * @version $Revision$
+ */
+public class ScheduleCompactMonthRenderer
+ extends AbstractCompactScheduleRenderer
+{
+ //~ Methods ----------------------------------------------------------------
+
+ /**
+ * @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeBegin(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ if (!component.isRendered()) {
+ return;
+ }
+
+ super.encodeBegin(context, component);
+
+ HtmlSchedule schedule = (HtmlSchedule) component;
+ Map attributes = schedule.getAttributes();
+ ResponseWriter writer = context.getResponseWriter();
+
+ //container div for the schedule grid
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "schedule-compact", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "border-style: none; overflow: hidden;", null
+ );
+
+ writer.startElement(HTML.TABLE_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "month", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "position: relative; left: 0px; top: 0px; width: 100%;",
+ null
+ );
+ writer.writeAttribute(HTML.CELLPADDING_ATTR, "0", null);
+ writer.writeAttribute(HTML.CELLSPACING_ATTR, "1", null);
+ writer.writeAttribute("border", "0", null);
+ writer.writeAttribute(HTML.WIDTH_ATTR, "100%", null);
+ writer.startElement(HTML.TBODY_ELEM, schedule);
+
+ Calendar cal = GregorianCalendar.getInstance();
+
+ for (
+ Iterator dayIterator = schedule.getModel().iterator();
+ dayIterator.hasNext();
+ ) {
+ ScheduleDay day = (ScheduleDay) dayIterator.next();
+ cal.setTime(day.getDate());
+
+ int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
+ int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
+ boolean isWeekend =
+ (dayOfWeek == Calendar.SATURDAY) ||
+ (dayOfWeek == Calendar.SUNDAY);
+
+ cal.setTime(day.getDate());
+
+ if (dayOfMonth == 1) { //fill the cells of the previous month
+
+ TreeSet previousMonth = new TreeSet();
+
+ while (cal.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
+ cal.add(Calendar.DATE, -1);
+ previousMonth.add(new ScheduleDay(cal.getTime()));
+ }
+
+ for (
+ Iterator prevMonthIterator = previousMonth.iterator();
+ prevMonthIterator.hasNext();
+ ) {
+ ScheduleDay d = (ScheduleDay) prevMonthIterator.next();
+ cal.setTime(d.getDate());
+
+ int dow = cal.get(Calendar.DAY_OF_WEEK);
+ int dom = cal.get(Calendar.DAY_OF_MONTH);
+ boolean w =
+ (dow == Calendar.SATURDAY) || (dow == Calendar.SUNDAY);
+ writeDayCell(
+ context, writer, schedule, d, dow, dom, w, false,
+ w ? 1 : 2
+ );
+ }
+ }
+
+ writeDayCell(
+ context, writer, schedule, day, dayOfWeek, dayOfMonth, isWeekend,
+ true, isWeekend ? 1 : 2
+ );
+
+ if (!dayIterator.hasNext()) { //fill the empty cells of the next month
+
+ while (cal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
+ cal.add(Calendar.DATE, 1);
+
+ ScheduleDay d = new ScheduleDay(cal.getTime());
+ int dow = cal.get(Calendar.DAY_OF_WEEK);
+ int dom = cal.get(Calendar.DAY_OF_MONTH);
+ boolean w =
+ (dow == Calendar.SATURDAY) || (dow == Calendar.SUNDAY);
+ writeDayCell(
+ context, writer, schedule, d, dow, dom, w, false,
+ w ? 1 : 2
+ );
+ }
+ }
+ }
+
+ writer.endElement(HTML.TBODY_ELEM);
+ writer.endElement(HTML.TABLE_ELEM);
+
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ /**
+ * @see org.apache.myfaces.custom.schedule.render.AbstractCompactScheduleRenderer#getDefaultRowHeight()
+ */
+ protected int getDefaultRowHeight()
+ {
+ return 120;
+ }
+
+ /**
+ * @see org.apache.myfaces.custom.schedule.render.AbstractCompactScheduleRenderer#getRowHeightProperty()
+ */
+ protected String getRowHeightProperty()
+ {
+ return "compactMonthRowHeight";
+ }
+
+ /**
+ * @see org.apache.myfaces.custom.schedule.render.AbstractCompactScheduleRenderer#writeDayCell(javax.faces.context.FacesContext,
+ * javax.faces.context.ResponseWriter,
+ * org.apache.myfaces.custom.schedule.HtmlSchedule,
+ * org.apache.myfaces.custom.schedule.model.ScheduleDay, int, int, int,
+ * boolean, boolean, int)
+ */
+ protected void writeDayCell(
+ FacesContext context,
+ ResponseWriter writer,
+ HtmlSchedule schedule,
+ ScheduleDay day,
+ int dayOfWeek,
+ int dayOfMonth,
+ boolean isWeekend,
+ boolean isCurrentMonth,
+ int rowspan
+ )
+ throws IOException
+ {
+ if ((dayOfWeek == Calendar.MONDAY) || (dayOfWeek == Calendar.SUNDAY)) {
+ writer.startElement(HTML.TR_ELEM, schedule);
+ }
+
+ super.writeDayCell(
+ context, writer, schedule, day, 100f / 6, dayOfWeek, dayOfMonth,
+ isWeekend, isCurrentMonth, rowspan
+ );
+
+ if ((dayOfWeek == Calendar.SATURDAY) || (dayOfWeek == Calendar.SUNDAY)) {
+ writer.endElement(HTML.TR_ELEM);
+ }
+ }
+}
+//The End
Added: myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleCompactWeekRenderer.java
URL: http://svn.apache.org/viewcvs/myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleCompactWeekRenderer.java?rev=216175&view=auto
==============================================================================
--- myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleCompactWeekRenderer.java (added)
+++ myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleCompactWeekRenderer.java Wed Jul 13 08:33:22 2005
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.myfaces.custom.schedule.renderer;
+
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import org.apache.myfaces.custom.schedule.HtmlSchedule;
+import org.apache.myfaces.custom.schedule.model.ScheduleDay;
+import org.apache.myfaces.renderkit.html.HTML;
+
+
+/**
+ * <p>
+ * Renderer for the week view of the UISchedule component
+ * </p>
+ *
+ * @author Jurgen Lust (latest modification by $Author$)
+ * @author Bruno Aranda (adaptation of Jurgen's code to myfaces)
+ * @version $Revision$
+ */
+public class ScheduleCompactWeekRenderer
+ extends AbstractCompactScheduleRenderer
+{
+ //~ Methods ----------------------------------------------------------------
+
+ /**
+ * @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeBegin(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ if (!component.isRendered()) {
+ return;
+ }
+
+ super.encodeBegin(context, component);
+
+ HtmlSchedule schedule = (HtmlSchedule) component;
+ Map attributes = schedule.getAttributes();
+ ResponseWriter writer = context.getResponseWriter();
+
+ //container div for the schedule grid
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "schedule-compact", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "border-style: none; overflow: hidden;", null
+ );
+
+ writer.startElement(HTML.TABLE_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "week", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "position: relative; left: 0px; top: 0px; width: 100%;",
+ null
+ );
+ writer.writeAttribute(HTML.CELLPADDING_ATTR, "0", null);
+ writer.writeAttribute(HTML.CELLSPACING_ATTR, "1", null);
+ writer.writeAttribute("border", "0", null);
+ writer.writeAttribute(HTML.WIDTH_ATTR, "100%", null);
+ writer.startElement(HTML.TBODY_ELEM, schedule);
+
+ Calendar cal = GregorianCalendar.getInstance();
+
+ for (
+ Iterator dayIterator = schedule.getModel().iterator();
+ dayIterator.hasNext();
+ ) {
+ ScheduleDay day = (ScheduleDay) dayIterator.next();
+ cal.setTime(day.getDate());
+
+ int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
+ int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
+ boolean isWeekend =
+ (dayOfWeek == Calendar.SATURDAY) ||
+ (dayOfWeek == Calendar.SUNDAY);
+
+ if (
+ (dayOfWeek == Calendar.MONDAY) ||
+ (dayOfWeek == Calendar.WEDNESDAY) ||
+ (dayOfWeek == Calendar.FRIDAY) ||
+ (dayOfWeek == Calendar.SUNDAY)
+ ) {
+ writer.startElement(HTML.TR_ELEM, schedule);
+ }
+
+ writeDayCell(
+ context, writer, schedule, day, 50f, dayOfWeek, dayOfMonth,
+ isWeekend, true, (dayOfWeek == Calendar.FRIDAY) ? 2 : 1
+ );
+
+ if (
+ (dayOfWeek == Calendar.TUESDAY) ||
+ (dayOfWeek == Calendar.THURSDAY) ||
+ (dayOfWeek == Calendar.SATURDAY) ||
+ (dayOfWeek == Calendar.SUNDAY)
+ ) {
+ writer.endElement(HTML.TR_ELEM);
+ }
+ }
+
+ writer.endElement(HTML.TBODY_ELEM);
+ writer.endElement(HTML.TABLE_ELEM);
+
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ /**
+ * @see org.apache.myfaces.custom.schedule.render.AbstractCompactScheduleRenderer#getDefaultRowHeight()
+ */
+ protected int getDefaultRowHeight()
+ {
+ return 200;
+ }
+
+ /**
+ * @see org.apache.myfaces.custom.schedule.render.AbstractCompactScheduleRenderer#getRowHeightProperty()
+ */
+ protected String getRowHeightProperty()
+ {
+ return "compactWeekRowHeight";
+ }
+}
+//The End
Added: myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleDelegatingRenderer.java
URL: http://svn.apache.org/viewcvs/myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleDelegatingRenderer.java?rev=216175&view=auto
==============================================================================
--- myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleDelegatingRenderer.java (added)
+++ myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleDelegatingRenderer.java Wed Jul 13 08:33:22 2005
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.myfaces.custom.schedule.renderer;
+
+
+import java.io.IOException;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.render.Renderer;
+
+import org.apache.myfaces.component.html.util.AddResource;
+import org.apache.myfaces.custom.schedule.HtmlSchedule;
+import org.apache.myfaces.custom.schedule.model.ScheduleModel;
+
+
+/**
+ * <p>
+ * Renderer for the Schedule component that delegates the actual rendering
+ * to a compact or detailed renderer, depending on the mode of the ScheduleModel
+ * </p>
+ *
+ * @author Jurgen Lust (latest modification by $Author$)
+ * @author Bruno Aranda (adaptation of Jurgen's code to myfaces)
+ * @version $Revision$
+ */
+public class ScheduleDelegatingRenderer
+ extends Renderer
+{
+ //~ Instance fields --------------------------------------------------------
+
+ private final ScheduleCompactMonthRenderer monthDelegate =
+ new ScheduleCompactMonthRenderer();
+ private final ScheduleCompactWeekRenderer weekDelegate =
+ new ScheduleCompactWeekRenderer();
+ private final ScheduleDetailedDayRenderer dayDelegate =
+ new ScheduleDetailedDayRenderer();
+
+ //~ Methods ----------------------------------------------------------------
+
+ /**
+ * @see javax.faces.render.Renderer#decode(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void decode(
+ FacesContext context,
+ UIComponent component
+ )
+ {
+ getDelegateRenderer(component).decode(context, component);
+ }
+
+ /**
+ * @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeBegin(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ AddResource.addStyleSheet(HtmlSchedule.class, "css/schedule.css", context);
+ getDelegateRenderer(component).encodeBegin(context, component);
+ }
+
+ /**
+ * @see javax.faces.render.Renderer#encodeChildren(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeChildren(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ getDelegateRenderer(component).encodeChildren(context, component);
+ }
+
+ /**
+ * @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeEnd(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ getDelegateRenderer(component).encodeEnd(context, component);
+ }
+
+ private Renderer getDelegateRenderer(UIComponent component)
+ {
+ HtmlSchedule schedule = (HtmlSchedule) component;
+
+ if ((schedule == null) || (schedule.getModel() == null)) {
+ return dayDelegate;
+ }
+
+ switch (schedule.getModel().getMode()) {
+ case ScheduleModel.WEEK:
+ return weekDelegate;
+
+ case ScheduleModel.MONTH:
+ return monthDelegate;
+
+ default:
+ return dayDelegate;
+ }
+ }
+}
+//The End
Added: myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleDetailedDayRenderer.java
URL: http://svn.apache.org/viewcvs/myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleDetailedDayRenderer.java?rev=216175&view=auto
==============================================================================
--- myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleDetailedDayRenderer.java (added)
+++ myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/ScheduleDetailedDayRenderer.java Wed Jul 13 08:33:22 2005
@@ -0,0 +1,832 @@
+/*
+ * Copyright 2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.myfaces.custom.schedule.renderer;
+
+
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.TreeSet;
+
+import javax.faces.component.UIComponent;
+import javax.faces.component.UIForm;
+import javax.faces.context.FacesContext;
+import javax.faces.context.ResponseWriter;
+
+import org.apache.myfaces.custom.schedule.HtmlSchedule;
+import org.apache.myfaces.custom.schedule.model.ScheduleDay;
+import org.apache.myfaces.custom.schedule.model.ScheduleEntry;
+import org.apache.myfaces.renderkit.html.HTML;
+
+
+/**
+ * <p>
+ * Renderer for the day and workweek views of the Schedule component
+ * </p>
+ *
+ * @author Jurgen Lust (latest modification by $Author$)
+ * @author Bruno Aranda (adaptation of Jurgen's code to myfaces)
+ * @version $Revision$
+ */
+public class ScheduleDetailedDayRenderer
+ extends AbstractScheduleRenderer
+{
+ //~ Instance fields --------------------------------------------------------
+
+ private final int rowHeightInPixels = 22;
+
+ //~ Methods ----------------------------------------------------------------
+
+ /**
+ * @see javax.faces.render.Renderer#encodeBegin(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeBegin(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ if (!component.isRendered()) {
+ return;
+ }
+
+ super.encodeBegin(context, component);
+
+ HtmlSchedule schedule = (HtmlSchedule) component;
+ Map attributes = schedule.getAttributes();
+ ResponseWriter writer = context.getResponseWriter();
+
+ //the number of rows in the grid is the number of half hours between
+ //visible start hour and visible end hour, plus 1 for the header
+ int numberOfRows =
+ ((schedule.getVisibleEndHour() - schedule.getVisibleStartHour()) * 2) +
+ 1;
+
+ //the grid height = 22 pixels times the number of rows + 3, for the
+ //table border and the cellpadding
+ int gridHeight = (numberOfRows * 22) + 3 + 10;
+
+ //container div for the schedule grid
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "schedule-detailed", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: " + String.valueOf(gridHeight) + "px; overflow: hidden;",
+ null
+ );
+ writeBackground(context, schedule, writer);
+ writeForegroundStart(context, schedule, writer);
+ }
+
+ /**
+ * @see javax.faces.render.Renderer#encodeChildren(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeChildren(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ if (!component.isRendered()) {
+ return;
+ }
+
+ HtmlSchedule schedule = (HtmlSchedule) component;
+ Map attributes = schedule.getAttributes();
+ ResponseWriter writer = context.getResponseWriter();
+
+ for (
+ Iterator dayIterator = schedule.getModel().iterator();
+ dayIterator.hasNext();
+ ) {
+ ScheduleDay day = (ScheduleDay) dayIterator.next();
+ writer.startElement(HTML.TD_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "column", null);
+ writer.writeAttribute(HTML.STYLE_ATTR, "height: 100%;", null);
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "column", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: relative; top: 0px; left: 0px; width: 100%; height: 100%; z-index: 0;",
+ null
+ );
+ writeEntries(context, schedule, day, writer);
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+ }
+ }
+
+ /**
+ * @see javax.faces.render.Renderer#encodeEnd(javax.faces.context.FacesContext,
+ * javax.faces.component.UIComponent)
+ */
+ public void encodeEnd(
+ FacesContext context,
+ UIComponent component
+ )
+ throws IOException
+ {
+ if (!component.isRendered()) {
+ return;
+ }
+
+ HtmlSchedule schedule = (HtmlSchedule) component;
+ Map attributes = schedule.getAttributes();
+ ResponseWriter writer = context.getResponseWriter();
+
+ writeForegroundEnd(context, schedule, writer);
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ private String getCellClass(
+ HtmlSchedule schedule,
+ int column,
+ int row
+ )
+ {
+ String cellClass = "free";
+ ScheduleDay day = (ScheduleDay) schedule.getModel().get(column);
+
+ if (!day.isWorkingDay()) {
+ return cellClass;
+ }
+
+ if (
+ ((schedule.getVisibleStartHour() + (row / 2)) >= schedule.getWorkingStartHour()) &&
+ ((schedule.getVisibleStartHour() + (row / 2)) < schedule.getWorkingEndHour())
+ ) {
+ cellClass = ((row % 2) == 0) ? "even" : "uneven";
+ }
+
+ return cellClass;
+ }
+
+ private boolean isSelected(
+ HtmlSchedule schedule,
+ EntryWrapper entry
+ )
+ {
+ ScheduleEntry selectedEntry = schedule.getModel().getSelectedEntry();
+
+ if (selectedEntry == null) {
+ return false;
+ }
+
+ boolean returnboolean =
+ selectedEntry.getId().equals(entry.entry.getId());
+
+ return returnboolean;
+ }
+
+ private void maximizeEntries(
+ EntryWrapper[] entries,
+ int numberOfColumns
+ )
+ {
+ for (int i = 0; i < entries.length; i++) {
+ EntryWrapper entry = entries[i];
+
+ //now see if we can expand the entry to the columns on the right
+ while (
+ ((entry.column + entry.colspan) < numberOfColumns) &&
+ entry.canFitInColumn(entry.column + entry.colspan)
+ ) {
+ entry.colspan++;
+ }
+ }
+ }
+
+ private void scanEntries(
+ EntryWrapper[] entries,
+ int index
+ )
+ {
+ if (entries.length <= 0) {
+ return;
+ }
+
+ EntryWrapper entry = entries[index];
+ entry.column = 0;
+
+ //see what columns are already taken
+ for (int i = 0; i < index; i++) {
+ if (entry.overlaps(entries[i])) {
+ entry.overlappingEntries.add(entries[i]);
+ entries[i].overlappingEntries.add(entry);
+ }
+ }
+
+ //find an available column
+ while (!entry.canFitInColumn(entry.column)) {
+ entry.column++;
+ }
+
+ //recursively scan the remaining entries for overlaps
+ if (++index < entries.length) {
+ scanEntries(entries, index);
+ }
+ }
+
+ private void writeBackground(
+ FacesContext context,
+ HtmlSchedule schedule,
+ ResponseWriter writer
+ )
+ throws IOException
+ {
+ //a calendar component should always be inside a UIForm
+ UIForm parentForm = getParentForm(schedule);
+
+ if (parentForm == null) {
+ throw new NullPointerException("No parent UIForm found");
+ }
+
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "background", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; z-index: 0;",
+ null
+ );
+
+ //background table for the schedule grid
+ writer.startElement(HTML.TABLE_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "background", null);
+ writer.writeAttribute(HTML.CELLPADDING_ATTR, "0", null);
+ writer.writeAttribute(HTML.CELLSPACING_ATTR, "1", null);
+ writer.writeAttribute(HTML.STYLE_ATTR, "width: 100%; height: 100%", null);
+ writer.startElement(HTML.TBODY_ELEM, schedule);
+
+ //header row, containing the column names
+ writer.startElement(HTML.TR_ELEM, schedule);
+ writer.startElement(HTML.TD_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "gutter", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: 21px; border-style: none; border-width: 0px; overflow: hidden; padding: 0px",
+ null
+ );
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.STYLE_ATTR, "height: 1px; width: 56px", null);
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+
+ float columnWidth =
+ (schedule.getModel().size() == 0) ? 100
+ : (100 / schedule.getModel().size());
+
+ for (
+ Iterator dayIterator = schedule.getModel().iterator();
+ dayIterator.hasNext();
+ ) {
+ ScheduleDay day = (ScheduleDay) dayIterator.next();
+ writer.startElement(HTML.TD_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "header", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: 31px; border-style: none; border-width: 0px; overflow: hidden;",
+ null
+ );
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(columnWidth) + "%", null
+ );
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: relative; left: 0px; top: 0px; width: 100%; height: 100%;",
+ null
+ );
+
+ //write the date
+ writer.startElement(HTML.SPAN_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "date", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: absolute; left: 0px; top: 0px; height: 15px; width: 100%; vertical-align: top; overflow: hidden; white-space: nowrap;",
+ null
+ );
+ writer.writeText(
+ getDateString(context, schedule.getAttributes(), day.getDate()),
+ null
+ );
+ writer.endElement(HTML.SPAN_ELEM);
+
+ //write the name of the holiday, if there is one
+ if (
+ (day.getSpecialDayName() != null) &&
+ (day.getSpecialDayName().length() > 0)
+ ) {
+ writer.startElement(HTML.SPAN_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "holiday", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: absolute; left: 0px; top: 15px; width: 100%; vertical-align: top; overflow: hidden; white-space: nowrap;",
+ null
+ );
+ writer.writeText(day.getSpecialDayName(), null);
+ writer.endElement(HTML.SPAN_ELEM);
+ }
+
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+
+ int numberOfRows =
+ (schedule.getVisibleEndHour() - schedule.getVisibleStartHour()) * 2;
+
+ for (int row = 0; row < numberOfRows; row++) {
+ writer.startElement(HTML.TR_ELEM, schedule);
+
+ //write the hours of the day on the left
+ //this only happens on even rows, or every hour
+ if ((row % 2) == 0) {
+ writer.startElement(HTML.TD_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "gutter", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: 21px; border-style: none; border-width: 0px; overflow: hidden; padding: 0px",
+ null
+ );
+ writer.writeAttribute("rowspan", "2", null);
+ writer.startElement(HTML.SPAN_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "hours", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "vertical-align: top; height: 100%; padding: 0px;",
+ null
+ );
+ writer.writeText(
+ String.valueOf(schedule.getVisibleStartHour() + (row / 2)),
+ null
+ );
+ writer.endElement(HTML.SPAN_ELEM);
+ writer.startElement(HTML.SPAN_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "minutes", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "vertical-align: top; height: 100%; padding: 0px;",
+ null
+ );
+ writer.writeText("00", null);
+ writer.endElement(HTML.SPAN_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ //write the cells of the day columns on this row
+ for (int column = 0; column < schedule.getModel().size();
+ column++
+ ) {
+ writer.startElement(HTML.TD_ELEM, schedule);
+ writer.writeAttribute(
+ HTML.CLASS_ATTR, getCellClass(schedule, column, row), null
+ );
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "overflow: hidden; height: 21px;", null
+ );
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(columnWidth) + "%", null
+ );
+ writer.write(HTML.NBSP_ENTITY);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+ }
+
+ writer.endElement(HTML.TBODY_ELEM);
+ writer.endElement(HTML.TABLE_ELEM);
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ private void writeEntries(
+ FacesContext context,
+ HtmlSchedule schedule,
+ ScheduleDay day,
+ ResponseWriter writer
+ )
+ throws IOException
+ {
+ TreeSet entrySet = new TreeSet();
+ Map attributes = schedule.getAttributes();
+
+ for (Iterator entryIterator = day.iterator(); entryIterator.hasNext();) {
+ entrySet.add(
+ new EntryWrapper((ScheduleEntry) entryIterator.next(), day)
+ );
+ }
+
+ EntryWrapper[] entries =
+ (EntryWrapper[]) entrySet.toArray(
+ new EntryWrapper[entrySet.size()]
+ );
+
+ //determine overlaps
+ scanEntries(entries, 0);
+
+ //determine the number of columns within this day
+ int maxColumn = 0;
+
+ for (
+ Iterator entryIterator = entrySet.iterator();
+ entryIterator.hasNext();
+ ) {
+ EntryWrapper wrapper = (EntryWrapper) entryIterator.next();
+ maxColumn = Math.max(wrapper.column, maxColumn);
+ }
+
+ int numberOfColumns = maxColumn + 1;
+
+ //make sure the entries take up all available space horizontally
+ maximizeEntries(entries, numberOfColumns);
+
+ //now determine the width in percent of 1 column
+ float columnWidth = 100 / numberOfColumns;
+
+ UIForm parentForm = getParentForm(schedule);
+
+ //and now draw the entries in the columns
+ for (
+ Iterator entryIterator = entrySet.iterator();
+ entryIterator.hasNext();
+ ) {
+ EntryWrapper wrapper = (EntryWrapper) entryIterator.next();
+
+ if (isSelected(schedule, wrapper)) {
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "entry-selected", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, wrapper.getBounds(schedule, columnWidth), null
+ );
+
+ //draw the tooltip
+ if (showTooltip(schedule.getAttributes())) {
+ writer.writeAttribute(
+ "onmouseover",
+ getTooltipText(wrapper.entry, schedule.getAttributes()),
+ null
+ );
+ }
+
+ //draw the contents of the selected entry
+ writer.startElement(HTML.DIV_ELEM, null);
+ writer.writeAttribute(HTML.CLASS_ATTR, "text", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, "height: 100%; width: 100%;", null
+ );
+ writer.startElement(HTML.SPAN_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "title", null);
+ writer.writeText(wrapper.entry.getTitle(), null);
+ writer.endElement(HTML.SPAN_ELEM);
+ writer.startElement("br", schedule);
+ writer.endElement("br");
+ writer.startElement(HTML.SPAN_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "subtitle", null);
+ writer.writeText(wrapper.entry.getSubtitle(), null);
+ writer.endElement(HTML.SPAN_ELEM);
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.DIV_ELEM);
+ } else {
+ //if the schedule is read-only, the entries should not be
+ //hyperlinks
+ writer.startElement(
+ schedule.isReadonly() ? HTML.DIV_ELEM : "a", schedule
+ );
+
+ //draw the tooltip
+ if (showTooltip(schedule.getAttributes())) {
+ writer.writeAttribute(
+ "onmouseover",
+ getTooltipText(wrapper.entry, schedule.getAttributes()),
+ null
+ );
+ }
+
+ if (!schedule.isReadonly()) {
+ writer.writeAttribute("href", "#", null);
+
+ String clientId = schedule.getClientId(context);
+ StringBuffer mousedown = new StringBuffer();
+ mousedown.append("document.forms['");
+ mousedown.append(parentForm.getClientId(context));
+ mousedown.append("']['");
+ mousedown.append(clientId);
+ mousedown.append("'].value='");
+ mousedown.append(wrapper.entry.getId());
+ mousedown.append("'; document.forms['");
+ mousedown.append(parentForm.getClientId(context));
+ mousedown.append("'].submit()");
+ writer.writeAttribute(
+ "onmousedown", mousedown.toString(), null
+ );
+ }
+
+ writer.writeAttribute(HTML.CLASS_ATTR, "entry", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR, wrapper.getBounds(schedule, columnWidth), null
+ );
+ writer.startElement(HTML.SPAN_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "title", null);
+ writer.writeText(wrapper.entry.getTitle(), null);
+ writer.endElement(HTML.SPAN_ELEM);
+ writer.startElement("br", schedule);
+ writer.endElement("br");
+ writer.startElement(HTML.SPAN_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "subtitle", null);
+ writer.writeText(wrapper.entry.getSubtitle(), null);
+ writer.endElement(HTML.SPAN_ELEM);
+ writer.endElement(schedule.isReadonly() ? HTML.DIV_ELEM : "a");
+ }
+ }
+ }
+
+ private void writeForegroundEnd(
+ FacesContext context,
+ HtmlSchedule schedule,
+ ResponseWriter writer
+ )
+ throws IOException
+ {
+ writer.endElement(HTML.TR_ELEM);
+ writer.endElement(HTML.TABLE_ELEM);
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ private void writeForegroundStart(
+ FacesContext context,
+ HtmlSchedule schedule,
+ ResponseWriter writer
+ )
+ throws IOException
+ {
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "foreground", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; z-index: 2;",
+ null
+ );
+
+ writer.startElement(HTML.TABLE_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "foreground", null);
+ writer.writeAttribute(HTML.CELLSPACING_ATTR, "1", null);
+ writer.writeAttribute(HTML.CELLPADDING_ATTR, "0", null);
+ writer.writeAttribute(HTML.STYLE_ATTR, "width: 100%; height: 100%", null);
+ writer.startElement(HTML.TR_ELEM, schedule);
+ writer.startElement(HTML.TD_ELEM, schedule);
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.STYLE_ATTR, "height: 1px; width: 56px", null);
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+
+ float columnWidth =
+ (schedule.getModel().size() == 0) ? 100
+ : (100 / schedule.getModel().size());
+
+ for (
+ Iterator dayIterator = schedule.getModel().iterator();
+ dayIterator.hasNext();
+ ) {
+ ScheduleDay day = (ScheduleDay) dayIterator.next();
+ writer.startElement(HTML.TD_ELEM, schedule);
+ writer.writeAttribute(HTML.CLASS_ATTR, "header", null);
+ writer.writeAttribute(
+ HTML.STYLE_ATTR,
+ "height: 31px; border-style: none; border-width: 0px; overflow: hidden;",
+ null
+ );
+ writer.writeAttribute(
+ HTML.WIDTH_ATTR, String.valueOf(columnWidth) + "%", null
+ );
+
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ writer.endElement(HTML.TR_ELEM);
+
+ writer.startElement(HTML.TR_ELEM, schedule);
+ writer.startElement(HTML.TD_ELEM, schedule);
+ writer.startElement(HTML.DIV_ELEM, schedule);
+ writer.writeAttribute(HTML.STYLE_ATTR, "height: 1px; width: 56px", null);
+ writer.endElement(HTML.DIV_ELEM);
+ writer.endElement(HTML.TD_ELEM);
+ }
+
+ //~ Inner Classes ----------------------------------------------------------
+
+ private class EntryWrapper
+ implements Comparable
+ {
+ //~ Static fields/initializers -----------------------------------------
+
+ private static final int HALF_HOUR = 1000 * 60 * 30;
+
+ //~ Instance fields ----------------------------------------------------
+
+ private final ScheduleDay day;
+ private final ScheduleEntry entry;
+ private final TreeSet overlappingEntries;
+ private int colspan;
+ private int column;
+
+ //~ Constructors -------------------------------------------------------
+
+ EntryWrapper(
+ ScheduleEntry entry,
+ ScheduleDay day
+ )
+ {
+ this.entry = entry;
+ this.day = day;
+ this.column = 0;
+ this.colspan = 1;
+ this.overlappingEntries = new TreeSet();
+ }
+
+ //~ Methods ------------------------------------------------------------
+
+ /**
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(Object o)
+ {
+ return comparator.compare(entry, o);
+ }
+
+ /**
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ public boolean equals(Object o)
+ {
+ if (o instanceof EntryWrapper) {
+ EntryWrapper other = (EntryWrapper) o;
+
+ boolean returnboolean =
+ (entry.getStartTime().equals(other.entry.getStartTime())) &&
+ (entry.getEndTime().equals(other.entry.getEndTime())) &&
+ (entry.getId().equals(other.entry.getId())) &&
+ (day.equals(other.day));
+ /*
+ new EqualsBuilder().append(
+ entry.getStartTime(), other.entry.getStartTime()
+ ).append(entry.getEndTime(), other.entry.getEndTime())
+ .append(
+ entry.getId(), other.entry.getId()
+ ).append(day, other.day).isEquals();
+ */
+ return returnboolean;
+ }
+
+ return false;
+ }
+
+ /**
+ * @see java.lang.Object#hashCode()
+ */
+ public int hashCode()
+ {
+ int returnint =
+ entry.getStartTime().hashCode() ^
+ entry.getEndTime().hashCode() ^
+ entry.getId().hashCode();
+
+ return returnint;
+ }
+
+ /**
+ * <p>
+ * Determine the bounds of this entry, in CSS position attributes
+ * </p>
+ *
+ * @param schedule the schedule
+ * @param columnWidth the width of a column
+ *
+ * @return the bounds
+ */
+ String getBounds(
+ HtmlSchedule schedule,
+ float columnWidth
+ )
+ {
+ float width = (columnWidth * colspan) - 0.5f;
+ float left = column * columnWidth;
+ Calendar cal = GregorianCalendar.getInstance();
+ cal.setTime(day.getDate());
+
+ int curyear = cal.get(Calendar.YEAR);
+ int curmonth = cal.get(Calendar.MONTH);
+ int curday = cal.get(Calendar.DATE);
+
+ cal.setTime(entry.getStartTime());
+ cal.set(curyear, curmonth, curday);
+
+ long startMillis = cal.getTimeInMillis();
+ cal.set(Calendar.HOUR_OF_DAY, schedule.getVisibleStartHour());
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+
+ long visibleStartMillis = cal.getTimeInMillis();
+ startMillis =
+ day.equalsDate(entry.getStartTime())
+ ? Math.max(startMillis, visibleStartMillis) : visibleStartMillis;
+ cal.setTime(entry.getEndTime());
+ cal.set(curyear, curmonth, curday);
+
+ long endMillis = cal.getTimeInMillis();
+ cal.set(Calendar.HOUR_OF_DAY, schedule.getVisibleEndHour());
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+
+ long visibleEndMillis = cal.getTimeInMillis();
+ endMillis =
+ day.equalsDate(entry.getEndTime())
+ ? Math.min(endMillis, visibleEndMillis) : visibleEndMillis;
+
+ int top =
+ (int) (((startMillis - visibleStartMillis) * rowHeightInPixels) / HALF_HOUR);
+ int height =
+ (int) (((endMillis - startMillis) * rowHeightInPixels) / HALF_HOUR);
+ StringBuffer buffer = new StringBuffer();
+ buffer.append("position: absolute; height: ");
+ buffer.append(height);
+ buffer.append("px; top: ");
+ buffer.append(top);
+ buffer.append("px; left: ");
+ buffer.append(left);
+ buffer.append("%; width: ");
+ buffer.append(width);
+ buffer.append(
+ "%; padding: 0px; overflow: hidden; border-width: 1.0px; border-style:solid;"
+ );
+
+ return buffer.toString();
+ }
+
+ /**
+ * <p>
+ * Can this entry fit in the specified column?
+ * </p>
+ *
+ * @param column the column
+ *
+ * @return whether the entry fits
+ */
+ boolean canFitInColumn(int column)
+ {
+ for (
+ Iterator overlapIterator = overlappingEntries.iterator();
+ overlapIterator.hasNext();
+ ) {
+ EntryWrapper overlap = (EntryWrapper) overlapIterator.next();
+
+ if (overlap.column == column) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * <p>
+ * Does this entry overlap with another?
+ * </p>
+ *
+ * @param other the other entry
+ *
+ * @return whether the entries overlap
+ */
+ boolean overlaps(EntryWrapper other)
+ {
+ if ((entry.getStartTime() == null) || (entry.getEndTime() == null)) {
+ return false;
+ }
+
+ boolean returnboolean =
+ (entry.getStartTime().before(other.entry.getEndTime()) &&
+ entry.getEndTime().after(other.entry.getStartTime()));
+
+ return returnboolean;
+ }
+ }
+}
+//The End