You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2005/11/29 21:13:21 UTC
svn commit: r349804 [5/11] - in
/myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule: ./
model/ renderer/ resource/css/ resource/javascript/ util/
Modified: 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=349804&r1=349803&r2=349804&view=diff
==============================================================================
--- myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/PlannerRenderer.java (original)
+++ myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/PlannerRenderer.java Tue Nov 29 12:12:53 2005
@@ -1,984 +1,984 @@
-/*
- * 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.el.ValueBinding;
-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.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;
- }
-
- HtmlPlanner planner = (HtmlPlanner) component;
- ResponseWriter writer = context.getResponseWriter();
-
- //determine the CSS file for the chosen theme
- String theme = getTheme(planner);
- if (theme == null || theme.length() < 1) theme = "default";
- String css = "css/" + theme + ".css";
-
- //add needed CSS and Javascript files to the header
-
- AddResource addResource = AddResource.getInstance(context);
- addResource.addStyleSheet(context, AddResource.HEADER_BEGIN, HtmlPlanner.class, css);
- addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN,
- HtmlPlanner.class, "javascript/alphaAPI.js");
- addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN,
- HtmlPlanner.class, "javascript/domLib.js");
- addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN,
- HtmlPlanner.class, "javascript/domTT.js");
- addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN,
- HtmlPlanner.class, "javascript/fadomatic.js");
-
-
- 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;
- 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))
- + "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;
- ResponseWriter writer = context.getResponseWriter();
- writeForegroundEnd(context, planner, writer);
- writer.endElement(HTML.DIV_ELEM);
- }
-
- /**
- * <p>
- * Determine the width of the left gutter
- * </p>
- *
- * @param component the component
- *
- * @return the gutter width in pixels
- */
- protected int getGutterWidth(UIComponent component)
- {
- try
- {
- //first check if the gutterWidthInPixels property is a
- //value binding expression
- ValueBinding binding = component.getValueBinding("gutterWidthInPixels");
- if (binding != null) {
- Integer value =
- (Integer) binding.getValue(
- FacesContext.getCurrentInstance()
- );
-
- if (value != null) {
- return value.intValue();
- }
- }
- //it's not a value binding expression, so check for the string value
- //in the attributes
- Map attributes = component.getAttributes();
- 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 component the component
- *
- * @return Returns the headerDateFormat.
- */
- protected String getHeaderDateFormat(UIComponent component)
- {
- //first check if the headerDateFormat property is a value binding expression
- ValueBinding binding = component.getValueBinding("headerDateFormat");
- if (binding != null) {
- String value =
- (String) binding.getValue(
- FacesContext.getCurrentInstance()
- );
-
- if (value != null) {
- return value;
- }
- }
- //it's not a value binding expression, so check for the string value
- //in the attributes
- Map attributes = component.getAttributes();
- 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 component the component
- *
- * @return whether to render the legend
- */
- protected boolean showLegend(UIComponent component)
- {
- //first check if the tooltip property is a value binding expression
- ValueBinding binding = component.getValueBinding("legend");
- if (binding != null) {
- Boolean value =
- (Boolean) binding.getValue(
- FacesContext.getCurrentInstance()
- );
-
- if (value != null) {
- return value.booleanValue();
- }
- }
- //it's not a value binding expression, so check for the string value
- //in the attributes
- Map attributes = component.getAttributes();
- return Boolean.valueOf((String) attributes.get("legend"))
- .booleanValue();
- }
-
- /**
- * <p>
- * The theme used when rendering the planner
- * </p>
- *
- * @param component the component
- *
- * @return the theme
- */
- protected String getTheme(UIComponent component) {
- //first check if the theme property is a value binding expression
- ValueBinding binding = component.getValueBinding("theme");
- if (binding != null) {
- String value =
- (String) binding.getValue(
- FacesContext.getCurrentInstance()
- );
-
- if (value != null) {
- return value;
- }
- }
- //it's not a value binding expression, so check for the string value
- //in the attributes
- Map attributes = component.getAttributes();
- return (String)attributes.get("theme");
- }
-
- /**
- * <p>
- * Should the tooltip be rendered?
- * </p>
- *
- * @param component the component
- *
- * @return whether or not tooltips should be rendered
- */
- protected boolean showTooltip(UIComponent component)
- {
- //first check if the tooltip property is a value binding expression
- ValueBinding binding = component.getValueBinding("tooltip");
- if (binding != null) {
- Boolean value =
- (Boolean) binding.getValue(
- FacesContext.getCurrentInstance()
- );
-
- if (value != null) {
- return value.booleanValue();
- }
- }
- //it's not a value binding expression, so check for the string value
- //in the attributes
- Map attributes = component.getAttributes();
- 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, UIComponent component, Date date)
- {
- DateFormat format;
- String pattern = getHeaderDateFormat(component);
-
- 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, UIComponent component)
- {
- if (!showTooltip(component))
- {
- return null;
- }
-
- 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))
- + "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,
- 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))
- {
- writer.writeAttribute("onmouseover", getTooltipText(
- wrapper.entry, planner), 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))
- + "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
+/*
+ * 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.el.ValueBinding;
+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.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;
+ }
+
+ HtmlPlanner planner = (HtmlPlanner) component;
+ ResponseWriter writer = context.getResponseWriter();
+
+ //determine the CSS file for the chosen theme
+ String theme = getTheme(planner);
+ if (theme == null || theme.length() < 1) theme = "default";
+ String css = "css/" + theme + ".css";
+
+ //add needed CSS and Javascript files to the header
+
+ AddResource addResource = AddResource.getInstance(context);
+ addResource.addStyleSheet(context, AddResource.HEADER_BEGIN, HtmlPlanner.class, css);
+ addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN,
+ HtmlPlanner.class, "javascript/alphaAPI.js");
+ addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN,
+ HtmlPlanner.class, "javascript/domLib.js");
+ addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN,
+ HtmlPlanner.class, "javascript/domTT.js");
+ addResource.addJavaScriptAtPosition(context, AddResource.HEADER_BEGIN,
+ HtmlPlanner.class, "javascript/fadomatic.js");
+
+
+ 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;
+ 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))
+ + "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;
+ ResponseWriter writer = context.getResponseWriter();
+ writeForegroundEnd(context, planner, writer);
+ writer.endElement(HTML.DIV_ELEM);
+ }
+
+ /**
+ * <p>
+ * Determine the width of the left gutter
+ * </p>
+ *
+ * @param component the component
+ *
+ * @return the gutter width in pixels
+ */
+ protected int getGutterWidth(UIComponent component)
+ {
+ try
+ {
+ //first check if the gutterWidthInPixels property is a
+ //value binding expression
+ ValueBinding binding = component.getValueBinding("gutterWidthInPixels");
+ if (binding != null) {
+ Integer value =
+ (Integer) binding.getValue(
+ FacesContext.getCurrentInstance()
+ );
+
+ if (value != null) {
+ return value.intValue();
+ }
+ }
+ //it's not a value binding expression, so check for the string value
+ //in the attributes
+ Map attributes = component.getAttributes();
+ 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 component the component
+ *
+ * @return Returns the headerDateFormat.
+ */
+ protected String getHeaderDateFormat(UIComponent component)
+ {
+ //first check if the headerDateFormat property is a value binding expression
+ ValueBinding binding = component.getValueBinding("headerDateFormat");
+ if (binding != null) {
+ String value =
+ (String) binding.getValue(
+ FacesContext.getCurrentInstance()
+ );
+
+ if (value != null) {
+ return value;
+ }
+ }
+ //it's not a value binding expression, so check for the string value
+ //in the attributes
+ Map attributes = component.getAttributes();
+ 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 component the component
+ *
+ * @return whether to render the legend
+ */
+ protected boolean showLegend(UIComponent component)
+ {
+ //first check if the tooltip property is a value binding expression
+ ValueBinding binding = component.getValueBinding("legend");
+ if (binding != null) {
+ Boolean value =
+ (Boolean) binding.getValue(
+ FacesContext.getCurrentInstance()
+ );
+
+ if (value != null) {
+ return value.booleanValue();
+ }
+ }
+ //it's not a value binding expression, so check for the string value
+ //in the attributes
+ Map attributes = component.getAttributes();
+ return Boolean.valueOf((String) attributes.get("legend"))
+ .booleanValue();
+ }
+
+ /**
+ * <p>
+ * The theme used when rendering the planner
+ * </p>
+ *
+ * @param component the component
+ *
+ * @return the theme
+ */
+ protected String getTheme(UIComponent component) {
+ //first check if the theme property is a value binding expression
+ ValueBinding binding = component.getValueBinding("theme");
+ if (binding != null) {
+ String value =
+ (String) binding.getValue(
+ FacesContext.getCurrentInstance()
+ );
+
+ if (value != null) {
+ return value;
+ }
+ }
+ //it's not a value binding expression, so check for the string value
+ //in the attributes
+ Map attributes = component.getAttributes();
+ return (String)attributes.get("theme");
+ }
+
+ /**
+ * <p>
+ * Should the tooltip be rendered?
+ * </p>
+ *
+ * @param component the component
+ *
+ * @return whether or not tooltips should be rendered
+ */
+ protected boolean showTooltip(UIComponent component)
+ {
+ //first check if the tooltip property is a value binding expression
+ ValueBinding binding = component.getValueBinding("tooltip");
+ if (binding != null) {
+ Boolean value =
+ (Boolean) binding.getValue(
+ FacesContext.getCurrentInstance()
+ );
+
+ if (value != null) {
+ return value.booleanValue();
+ }
+ }
+ //it's not a value binding expression, so check for the string value
+ //in the attributes
+ Map attributes = component.getAttributes();
+ 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, UIComponent component, Date date)
+ {
+ DateFormat format;
+ String pattern = getHeaderDateFormat(component);
+
+ 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, UIComponent component)
+ {
+ if (!showTooltip(component))
+ {
+ return null;
+ }
+
+ 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))
+ + "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,
+ 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))
+ {
+ writer.writeAttribute("onmouseover", getTooltipText(
+ wrapper.entry, planner), 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))
+ + "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
Propchange: myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/PlannerRenderer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: myfaces/sandbox/trunk/src/java/org/apache/myfaces/custom/schedule/renderer/PlannerRenderer.java
------------------------------------------------------------------------------
svn:keywords = Date Author Id Revision HeadURL