mirror of
https://github.com/atlanticbiomedical/portal.git
synced 2025-07-01 01:57:28 -04:00
Fixed 'Tetris' calendar problem.
This commit is contained in:
16
.classpath
16
.classpath
@ -9,8 +9,6 @@
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/guice-assistedinject-3.0.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/guice-servlet-3.0.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/gwt-bootstrap-2.1.1.0-SNAPSHOT.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/gwt-cal-0.9.3.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/gwt-dnd-3.1.2.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/gwt-maps.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/javax.inject.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/jsr305-1.3.9.jar"/>
|
||||
@ -32,18 +30,8 @@
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/transaction-api-1.1.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/xpp3-1.1.4c.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/args4j-2.0.21.jar"/>
|
||||
<classpathentry kind="lib" path="war/WEB-INF/lib/gwt-dnd-3.1.2.jar"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="lib" path="/home/akira/gwt-2.5.0.rc1/gwt-user.jar">
|
||||
<attributes>
|
||||
<attribute name="javadoc_location" value="file:/home/akira/gwt-2.5.0.rc1/doc/javadoc/"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="/home/akira/gwt-2.5.0.rc1/gwt-dev.jar">
|
||||
<attributes>
|
||||
<attribute name="javadoc_location" value="file:/home/akira/gwt-2.5.0.rc1/doc/javadoc/"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="lib" path="/home/akira/gwt-2.5.0.rc1/validation-api-1.0.0.GA.jar" sourcepath="/home/akira/gwt-2.5.0.rc1/validation-api-1.0.0.GA-sources.jar"/>
|
||||
<classpathentry kind="lib" path="/home/akira/gwt-2.5.0.rc1/validation-api-1.0.0.GA-sources.jar"/>
|
||||
<classpathentry kind="con" path="com.google.gwt.eclipse.core.GWT_CONTAINER"/>
|
||||
<classpathentry kind="output" path="war/WEB-INF/classes"/>
|
||||
</classpath>
|
||||
|
2
.settings/com.google.appengine.eclipse.core.prefs
Normal file
2
.settings/com.google.appengine.eclipse.core.prefs
Normal file
@ -0,0 +1,2 @@
|
||||
eclipse.preferences.version=1
|
||||
filesCopiedToWebInfLib=
|
@ -1,3 +1,4 @@
|
||||
eclipse.preferences.version=1
|
||||
entryPointModules=
|
||||
filesCopiedToWebInfLib=gwt-servlet.jar
|
||||
gwtCompileSettings=PGd3dC1jb21waWxlLXNldHRpbmdzPjxsb2ctbGV2ZWw+SU5GTzwvbG9nLWxldmVsPjxvdXRwdXQtc3R5bGU+T0JGVVNDQVRFRDwvb3V0cHV0LXN0eWxlPjxleHRyYS1hcmdzPjwhW0NEQVRBW11dPjwvZXh0cmEtYXJncz48dm0tYXJncz48IVtDREFUQVstWG14NTEybV1dPjwvdm0tYXJncz48ZW50cnktcG9pbnQtbW9kdWxlPmNvbS5iaW9tZWQuQmlvbWVkPC9lbnRyeS1wb2ludC1tb2R1bGU+PC9nd3QtY29tcGlsZS1zZXR0aW5ncz4\=
|
||||
|
7
server.properties
Normal file
7
server.properties
Normal file
@ -0,0 +1,7 @@
|
||||
email.username=schedule
|
||||
email.password=success4
|
||||
database.host=biomed.akira.gs:3306
|
||||
database.name=biomed_devel
|
||||
database.username=biomed_devel
|
||||
database.password=pXVt9QMSq8XURfXm
|
||||
devmode=true
|
@ -0,0 +1,181 @@
|
||||
package com.allen_sauer.gwt.dnd.client.drop;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.allen_sauer.gwt.dnd.client.DragContext;
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.dayview.AppointmentWidget;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public class DayViewDropController extends AbsolutePositionDropController {
|
||||
|
||||
private int gridX;
|
||||
|
||||
private int gridY;
|
||||
int dayStartsAt = 0;
|
||||
private int intervalsPerHour;
|
||||
private int snapSize;
|
||||
private int columns;
|
||||
private int rows;
|
||||
private Date date;
|
||||
private int maxProxyHeight = -1;
|
||||
|
||||
public void setColumns(final int columns) {
|
||||
this.columns = columns;
|
||||
}
|
||||
|
||||
public void setDate(final Date date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public void setSnapSize(final int snapSize) {
|
||||
this.snapSize = snapSize;
|
||||
}
|
||||
|
||||
public void setIntervalsPerHour(final int intervalsPerHour) {
|
||||
this.intervalsPerHour = intervalsPerHour;
|
||||
this.rows = intervalsPerHour * 24;
|
||||
}
|
||||
|
||||
public void setDayStartsAt(final int dayStartsAt) {
|
||||
this.dayStartsAt = dayStartsAt;
|
||||
}
|
||||
|
||||
public void setMaxProxyHeight(final int maxProxyHeight) {
|
||||
this.maxProxyHeight = maxProxyHeight;
|
||||
}
|
||||
|
||||
public DayViewDropController(final AbsolutePanel dropTarget) {
|
||||
super(dropTarget);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void onDrop(final DragContext context) {
|
||||
|
||||
super.onDrop(context);
|
||||
|
||||
//get the top and left position and the widget
|
||||
int top =draggableList.get(0).desiredY;
|
||||
int left=draggableList.get(0).desiredX;
|
||||
Widget widget = context.draggable;
|
||||
|
||||
//set the 'snapped' top and left position of the widget
|
||||
left = Math.max(0, Math.min(left, dropTarget.getOffsetWidth() - widget.getOffsetWidth()));
|
||||
top = Math.max(0, Math.min(top, dropTarget.getOffsetHeight() - widget.getOffsetHeight()));
|
||||
left = Math.round((float) left / gridX) * gridX;
|
||||
top = Math.round((float) top / gridY) * gridY;
|
||||
|
||||
//figure out which row the appointment was dragged to
|
||||
int intervalStart = (int) Math.floor(top / gridY);
|
||||
int intervalSpan = Math.round(widget.getOffsetHeight() / snapSize);
|
||||
|
||||
//figure out which day (column) the appointment was dragged to
|
||||
int day = (int) Math.floor(left / gridX);
|
||||
day = Math.max(0, day);
|
||||
day = Math.min(day, columns - 1);
|
||||
|
||||
//get the appointment, create the start & end date
|
||||
Appointment appt = ((AppointmentWidget)widget).getAppointment();
|
||||
Date start = (Date)date.clone();
|
||||
Date end = (Date)date.clone();
|
||||
start.setDate(start.getDate()+day);
|
||||
end.setDate(end.getDate()+day);
|
||||
|
||||
start.setHours(dayStartsAt);
|
||||
start.setMinutes(0);
|
||||
start.setSeconds(0);
|
||||
start.setMinutes((intervalStart)*(60/intervalsPerHour));
|
||||
end.setHours(dayStartsAt);
|
||||
end.setMinutes(0);
|
||||
end.setSeconds(0);
|
||||
end.setMinutes((intervalStart + intervalSpan)*(60/intervalsPerHour));
|
||||
|
||||
|
||||
appt.setStart(start);
|
||||
appt.setEnd(end);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// @Override
|
||||
// public void drop(Widget widget, int left, int top) {
|
||||
//
|
||||
// }
|
||||
|
||||
// @Override
|
||||
// public void drop(Widget widget, int left, int top) {
|
||||
// left = Math.max(0, Math.min(left, dropTarget.getOffsetWidth() - widget.getOffsetWidth()));
|
||||
// top = Math.max(0, Math.min(top, dropTarget.getOffsetHeight() - widget.getOffsetHeight()));
|
||||
// left = Math.round((float) left / gridX) * gridX;
|
||||
// top = Math.round((float) top / gridY) * gridY;
|
||||
//
|
||||
// System.out.println("on drop");
|
||||
//
|
||||
//
|
||||
// int intervalStart = (int) Math.floor(top / rows);
|
||||
// int intervalSpan = 2;
|
||||
// int day = (int) Math.floor(left / columns);
|
||||
// day = Math.min(0, day);
|
||||
// day = Math.min(day, columns);
|
||||
// day = day-1; //convert to a 0-based day index
|
||||
//
|
||||
// Appointment appt = ((AppointmentWidget)widget).getAppointment();
|
||||
// Date start = (Date)date.clone();
|
||||
// Date end = (Date)date.clone();
|
||||
//
|
||||
// start.setDate(start.getDate()+day);
|
||||
// end.setDate(end.getDate()+day);
|
||||
//
|
||||
// start.setHours(0);
|
||||
// start.setMinutes((intervalStart)*(60/intervalsPerHour));
|
||||
// end.setHours(0);
|
||||
// end.setMinutes((intervalStart + intervalSpan)*(60/intervalsPerHour));
|
||||
//
|
||||
// System.out.println("new start: "+start);
|
||||
//
|
||||
// appt.setStart(start);
|
||||
// appt.setEnd(end);
|
||||
//
|
||||
//
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void onMove(final DragContext context) {
|
||||
super.onMove(context);
|
||||
|
||||
gridX = (int) Math.floor(dropTarget.getOffsetWidth() / columns);
|
||||
gridY = (int) Math.floor(dropTarget.getOffsetHeight() / rows);
|
||||
|
||||
|
||||
for (Draggable draggable : draggableList) {
|
||||
draggable.desiredX = context.desiredDraggableX - dropTargetOffsetX + draggable.relativeX;
|
||||
draggable.desiredY = context.desiredDraggableY - dropTargetOffsetY + draggable.relativeY;
|
||||
|
||||
draggable.desiredX = Math.max(0, Math.min(draggable.desiredX, dropTargetClientWidth - draggable.offsetWidth));
|
||||
draggable.desiredY = Math.max(0, Math.min(draggable.desiredY, dropTargetClientHeight - draggable.offsetHeight));
|
||||
draggable.desiredX = (int)Math.floor((double) draggable.desiredX / gridX) * gridX;
|
||||
draggable.desiredY = (int)Math.round((double) draggable.desiredY / gridY) * gridY;
|
||||
|
||||
dropTarget.add(draggable.positioner, draggable.desiredX, draggable.desiredY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnter(final DragContext context) {
|
||||
super.onEnter(context);
|
||||
|
||||
for (Draggable draggable : draggableList) {
|
||||
int width = draggable.positioner.getOffsetWidth();
|
||||
int height = draggable.positioner.getOffsetHeight();
|
||||
if (maxProxyHeight > 0 && height > maxProxyHeight) {
|
||||
height = maxProxyHeight - 5;
|
||||
}
|
||||
|
||||
draggable.positioner.setPixelSize(width, height);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.allen_sauer.gwt.dnd.client.drop;
|
||||
|
||||
import com.allen_sauer.gwt.dnd.client.DragContext;
|
||||
import com.allen_sauer.gwt.dnd.client.PickupDragController;
|
||||
import com.allen_sauer.gwt.dnd.client.util.DragClientBundle;
|
||||
import com.allen_sauer.gwt.dnd.client.util.WidgetArea;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public class DayViewPickupDragController extends PickupDragController {
|
||||
|
||||
private int maxProxyHeight = -1;
|
||||
|
||||
public DayViewPickupDragController(AbsolutePanel boundaryPanel,
|
||||
boolean allowDroppingOnBoundaryPanel) {
|
||||
super(boundaryPanel, allowDroppingOnBoundaryPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dragMove() {
|
||||
try {
|
||||
super.dragMove();
|
||||
} catch (NullPointerException ex) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Widget newDragProxy(DragContext context) {
|
||||
AbsolutePanel container = new AbsolutePanel();
|
||||
container.getElement().getStyle().setProperty("overflow", "visible");
|
||||
|
||||
WidgetArea draggableArea = new WidgetArea(context.draggable, null);
|
||||
for (Widget widget : context.selectedWidgets) {
|
||||
WidgetArea widgetArea = new WidgetArea(widget, null);
|
||||
Widget proxy = new SimplePanel();
|
||||
int height = widget.getOffsetHeight();
|
||||
if (maxProxyHeight > 0 && height > maxProxyHeight) {
|
||||
height = maxProxyHeight - 5;
|
||||
}
|
||||
|
||||
proxy.setPixelSize(widget.getOffsetWidth(), height);
|
||||
proxy.addStyleName(DragClientBundle.INSTANCE.css().proxy());
|
||||
container.add(proxy,
|
||||
widgetArea.getLeft() - draggableArea.getLeft(),
|
||||
widgetArea.getTop() - draggableArea.getTop());
|
||||
}
|
||||
|
||||
return container;
|
||||
}
|
||||
|
||||
public void setMaxProxyHeight(int maxProxyHeight) {
|
||||
this.maxProxyHeight = maxProxyHeight;
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package com.allen_sauer.gwt.dnd.client.drop;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.allen_sauer.gwt.dnd.client.AbstractDragController;
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.dayview.AppointmentWidget;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public class DayViewResizeController extends AbstractDragController {
|
||||
|
||||
public DayViewResizeController(AbsolutePanel boundaryPanel) {
|
||||
super(boundaryPanel);
|
||||
}
|
||||
|
||||
int dayStartsAt = 0;
|
||||
int snapSize;
|
||||
int intervalsPerHour;
|
||||
|
||||
public void setSnapSize(int snapSize) {
|
||||
this.snapSize = snapSize;
|
||||
}
|
||||
|
||||
public void setIntervalsPerHour(int intervalsPerHour) {
|
||||
this.intervalsPerHour = intervalsPerHour;
|
||||
}
|
||||
|
||||
public void setDayStartsAt(int dayStartsAt) {
|
||||
this.dayStartsAt = dayStartsAt;
|
||||
}
|
||||
|
||||
public void dragMove() {
|
||||
|
||||
Widget appointment = context.draggable.getParent();
|
||||
|
||||
//calculates difference between elements position on screen
|
||||
// and how many pixels the user is trying to drag it
|
||||
int delta = context.draggable.getAbsoluteTop()
|
||||
- context.desiredDraggableY;
|
||||
|
||||
//get the height of the widget
|
||||
int contentHeight = appointment.getOffsetHeight();
|
||||
|
||||
//make sure the height of the widget is not < the minimum size
|
||||
int newHeight = Math.max(contentHeight - delta, snapSize);
|
||||
|
||||
//get the 'snapped' height. basically it gets the rounded
|
||||
// intervals spanned, then multiples it by the snapSize
|
||||
int snapHeight = Math.round(
|
||||
(float) newHeight / snapSize) * snapSize;
|
||||
|
||||
appointment.setHeight(snapHeight + "px");
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void dragEnd() {
|
||||
AppointmentWidget apptWidget = (AppointmentWidget)context.draggable.getParent();
|
||||
int apptHeight = apptWidget.getOffsetHeight();
|
||||
Appointment appt = apptWidget.getAppointment();
|
||||
|
||||
|
||||
//get the start date
|
||||
Date end = (Date)appt.getStart().clone();
|
||||
|
||||
//get the "top" location of the appointment widget
|
||||
float topFloat = DOM.getIntStyleAttribute(apptWidget.getElement(), "top");
|
||||
|
||||
//get the grid span
|
||||
//int intervalStart = Math.round(topFloat / snapSize);
|
||||
int intervalSpan = Math.round(apptHeight / snapSize);
|
||||
|
||||
//set the end based on the new dragged value
|
||||
//end.setHours(dayStartsAt);
|
||||
end.setMinutes(end.getMinutes() + intervalSpan * (60 / intervalsPerHour));
|
||||
|
||||
//update the end
|
||||
appt.setEnd(end);
|
||||
|
||||
super.dragEnd();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009,2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.allen_sauer.gwt.dnd.client.drop;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.allen_sauer.gwt.dnd.client.DragContext;
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
import com.bradrydzewski.gwt.calendar.client.monthview.AppointmentWidget;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
|
||||
/**
|
||||
* Controls the Move and Drop (after dragging) events that can be generated in
|
||||
* the Month View.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class MonthViewDropController extends AbsolutePositionDropController {
|
||||
|
||||
private int daysPerWeek;
|
||||
private int weeksPerMonth;
|
||||
private Date firstDateDisplayed;
|
||||
|
||||
/**
|
||||
* Flextable that displays a Month in grid format.
|
||||
*/
|
||||
final private FlexTable monthGrid;
|
||||
|
||||
/**
|
||||
* List of all cells currently highlighted as an appointment is being
|
||||
* dragged.
|
||||
*/
|
||||
private Element[] highlightedCells;
|
||||
private static final String BACKGROUND = "backgroundColor";
|
||||
|
||||
public MonthViewDropController(final AbsolutePanel dropTarget,
|
||||
final FlexTable monthGrid) {
|
||||
|
||||
super(dropTarget);
|
||||
this.monthGrid = monthGrid;
|
||||
}
|
||||
|
||||
public void setDaysPerWeek(final int daysPerWeek) {
|
||||
this.daysPerWeek = daysPerWeek;
|
||||
}
|
||||
|
||||
public void setWeeksPerMonth(final int weeksPerMonth) {
|
||||
this.weeksPerMonth = weeksPerMonth;
|
||||
}
|
||||
|
||||
public Date getFirstDateDisplayed() {
|
||||
return firstDateDisplayed;
|
||||
}
|
||||
|
||||
public void setFirstDateDisplayed(final Date firstDateDisplayed) {
|
||||
this.firstDateDisplayed = firstDateDisplayed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manages the highlighting of cells in the month view grid when an
|
||||
* <code>Appointment</code> is being dragged.
|
||||
*
|
||||
* @param context An object providing information about the object being
|
||||
* dragged
|
||||
*/
|
||||
@Override
|
||||
public void onMove(final DragContext context) {
|
||||
//super.onMove(context);
|
||||
|
||||
//get the draggable object
|
||||
Draggable draggable = draggableList.get(0);
|
||||
|
||||
//make sure it isn't null (shouldn't ever be)
|
||||
if (draggable == null)
|
||||
return;
|
||||
|
||||
int col = getColumn(context, draggable);
|
||||
int row = getRow(context, draggable);
|
||||
|
||||
Element currHoveredCell =
|
||||
monthGrid.getFlexCellFormatter().getElement(row, col);
|
||||
|
||||
//If this cell isn't already highlighted, we need to highlight
|
||||
if (highlightedCells == null || highlightedCells.length < 0 ||
|
||||
!currHoveredCell.equals(highlightedCells[0])) {
|
||||
|
||||
if (highlightedCells != null) {
|
||||
for (Element elem : highlightedCells) {
|
||||
if (elem != null)
|
||||
DOM.setStyleAttribute(elem, BACKGROUND, "#FFFFFF");
|
||||
}
|
||||
}
|
||||
|
||||
Date startDate =
|
||||
((AppointmentWidget) draggable.widget).getAppointment().getStart();
|
||||
Date endDate =
|
||||
((AppointmentWidget) draggable.widget).getAppointment().getEnd();
|
||||
|
||||
int dateDiff = DateUtils.differenceInDays(endDate, startDate) + 1;
|
||||
dateDiff = (dateDiff <= 0) ? 1 : dateDiff;
|
||||
highlightedCells = getCells(row, col, dateDiff);
|
||||
|
||||
//TODO: month view highlighted cell style be moved to the css style sheet
|
||||
for (Element elem : highlightedCells) {
|
||||
if (elem != null) {
|
||||
DOM.setStyleAttribute(elem, BACKGROUND, "#C3D9FF");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method executed once the drag has completed. We need to reset the
|
||||
* background color of all previously highlighted cells. Also need to
|
||||
* actually change the appointment's start / end date here (code doesn't
|
||||
* exist yet).
|
||||
*
|
||||
* @param context An object containing information of what was dragged and
|
||||
* dropped, including the <code>Appointment</code>,
|
||||
* coordinates of the drop, etc.
|
||||
*/
|
||||
@Override
|
||||
public void onDrop(final DragContext context) {
|
||||
super.onDrop(context);
|
||||
|
||||
for (Element elem : highlightedCells) {
|
||||
if (elem != null) {
|
||||
DOM.setStyleAttribute(elem, BACKGROUND, "#FFFFFF");
|
||||
}
|
||||
}
|
||||
highlightedCells = null;
|
||||
|
||||
Draggable draggable = draggableList.get(0);
|
||||
|
||||
Appointment appointment =
|
||||
((AppointmentWidget) context.draggable).getAppointment();
|
||||
|
||||
long originalStartToEndTimeDistance =
|
||||
appointment.getEnd().getTime() - appointment.getStart().getTime();
|
||||
|
||||
//get the column and row for the draggable widget
|
||||
int row = getRow(context, draggable) - 1;
|
||||
int col = getColumn(context, draggable);
|
||||
int cell = row * daysPerWeek + col;
|
||||
|
||||
//calculate the new start & end dates
|
||||
Date newStart = DateUtils.shiftDate(firstDateDisplayed, cell);
|
||||
DateUtils.copyTime(appointment.getStart(), newStart);
|
||||
|
||||
Date newEnd = new Date(newStart.getTime() + originalStartToEndTimeDistance);
|
||||
|
||||
//Set the appointment's new start & end dates
|
||||
appointment.setStart(newStart);
|
||||
appointment.setEnd(newEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the cells (as DOM Elements) that an appointment spans. Note: It
|
||||
* only includes cells in the table. If an appointment ends in the following
|
||||
* month the last cell in the list will be the last cell in the table.
|
||||
*
|
||||
* @param row Appointment's starting row
|
||||
* @param col Appointment's starting column
|
||||
* @param days Number of days an appointment spans
|
||||
* @return Cell elements that an appointment spans
|
||||
*/
|
||||
protected Element[] getCells(int row, int col, int days) {
|
||||
|
||||
Element[] elems = new Element[days];
|
||||
|
||||
for (int i = 0; i < days; i++) {
|
||||
if (col > daysPerWeek - 1) {
|
||||
col = 0;
|
||||
row++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cheap code here. If the row / cell throw an out of index exception
|
||||
* we just break. This kind of sucks because we have to
|
||||
* now account for null items in the Element[] array.
|
||||
*/
|
||||
try {
|
||||
elems[i] = monthGrid.getFlexCellFormatter().getElement(row, col);
|
||||
} catch (Exception ex) {
|
||||
break;
|
||||
}
|
||||
|
||||
col++;
|
||||
}
|
||||
|
||||
return elems;
|
||||
}
|
||||
|
||||
public int getRow(final DragContext context, final Draggable draggable) {
|
||||
int y =
|
||||
context.desiredDraggableY - dropTargetOffsetY + draggable.relativeY;
|
||||
return (int)
|
||||
Math.floor(y / (monthGrid.getOffsetHeight() / weeksPerMonth)) + 1;
|
||||
}
|
||||
|
||||
public int getColumn(final DragContext context, final Draggable draggable) {
|
||||
int x =
|
||||
context.desiredDraggableX - dropTargetOffsetX + draggable.relativeX;
|
||||
return (int)
|
||||
Math.floor(x / (monthGrid.getOffsetWidth() / daysPerWeek));
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.allen_sauer.gwt.dnd.client.drop;
|
||||
|
||||
import com.allen_sauer.gwt.dnd.client.PickupDragController;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
|
||||
public class MonthViewPickupDragController extends PickupDragController {
|
||||
|
||||
public MonthViewPickupDragController(AbsolutePanel boundaryPanel,
|
||||
boolean allowDroppingOnBoundaryPanel) {
|
||||
super(boundaryPanel, allowDroppingOnBoundaryPanel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dragMove() {
|
||||
try {
|
||||
super.dragMove();
|
||||
} catch(NullPointerException ex) { }
|
||||
}
|
||||
}
|
@ -43,4 +43,7 @@
|
||||
<replace-with class="com.biomed.client.resources.BiomedDayViewStyleManager">
|
||||
<when-type-is class="com.bradrydzewski.gwt.calendar.client.dayview.DayViewStyleManager"/>
|
||||
</replace-with>
|
||||
<replace-with class="com.biomed.client.resources.BiomedTechViewStyleManager">
|
||||
<when-type-is class="com.bradrydzewski.gwt.calendar.client.techview.TechViewStyleManager"/>
|
||||
</replace-with>
|
||||
</module>
|
@ -0,0 +1,18 @@
|
||||
package com.biomed.client.resources;
|
||||
|
||||
import com.biomed.client.ui.schedule.BiomedAppointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.ThemeAppointmentStyle;
|
||||
import com.bradrydzewski.gwt.calendar.client.techview.TechViewStyleManager;
|
||||
|
||||
public class BiomedTechViewStyleManager extends TechViewStyleManager {
|
||||
@Override
|
||||
protected ThemeAppointmentStyle getDefaultViewAppointmentStyleForTheme() {
|
||||
return BiomedAppointmentTheme.GRAY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ThemeAppointmentStyle getViewAppointmentStyleForTheme(Appointment appointment) {
|
||||
return ((BiomedAppointment) appointment).getTheme();
|
||||
}
|
||||
}
|
@ -2,15 +2,20 @@ package com.biomed.client.ui.schedule;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.biomed.client.resources.BiomedAppointmentTheme;
|
||||
import com.biomed.client.ui.renderers.UserDTORenderer;
|
||||
import com.biomed.shared.api.dto.UserDTO;
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.Calendar;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarViews;
|
||||
import com.github.gwtbootstrap.client.ui.ValueListBox;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gwt.core.client.JsArray;
|
||||
import com.google.gwt.event.logical.shared.ResizeEvent;
|
||||
import com.google.gwt.event.logical.shared.ResizeHandler;
|
||||
@ -20,6 +25,8 @@ import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.HTMLPanel;
|
||||
import com.google.gwt.user.client.ui.HasConstrainedValue;
|
||||
import com.google.gwt.user.datepicker.client.DateBox;
|
||||
import com.google.maps.gwt.client.Geocoder;
|
||||
import com.google.maps.gwt.client.Geocoder.Callback;
|
||||
import com.google.maps.gwt.client.GeocoderRequest;
|
||||
@ -44,6 +51,12 @@ public class SchedulePanel extends Composite implements Schedule.View {
|
||||
@UiField
|
||||
FlowPanel mapContainer;
|
||||
|
||||
@UiField
|
||||
DateBox datePicker;
|
||||
|
||||
@UiField(provided = true)
|
||||
ValueListBox<UserDTO> techPicker;
|
||||
|
||||
private static final LatLng center = LatLng.create(39.257147, -76.685686);
|
||||
|
||||
private Calendar calendar;
|
||||
@ -55,6 +68,7 @@ public class SchedulePanel extends Composite implements Schedule.View {
|
||||
|
||||
@Inject
|
||||
public SchedulePanel(Binder binder) {
|
||||
techPicker = new ValueListBox<UserDTO>(new UserDTORenderer("All"));
|
||||
initWidget(binder.createAndBindUi(this));
|
||||
|
||||
buildCalendar();
|
||||
@ -99,7 +113,7 @@ public class SchedulePanel extends Composite implements Schedule.View {
|
||||
|
||||
calendar = new Calendar();
|
||||
calendar.setSettings(settings);
|
||||
calendar.setView(CalendarViews.DAY);
|
||||
calendar.setView(CalendarViews.TECH);
|
||||
calendar.setWidth("100%");
|
||||
calendar.setHeight("100%");
|
||||
calContainer.add(calendar);
|
||||
@ -115,8 +129,11 @@ public class SchedulePanel extends Composite implements Schedule.View {
|
||||
}
|
||||
markers.clear();
|
||||
|
||||
int columnId = -1;
|
||||
Map<Integer, Integer> columnMap = Maps.newHashMap();
|
||||
|
||||
for (Workorder w : workorders) {
|
||||
String address = null;
|
||||
String address = null;
|
||||
if (w.clientAddress != null) {
|
||||
address = w.clientAddress + "\n" + w.clientCity + ", " + w.clientState + ". " + w.clientZip;
|
||||
}
|
||||
@ -132,6 +149,14 @@ public class SchedulePanel extends Composite implements Schedule.View {
|
||||
apt.setStart(w.jobStart);
|
||||
apt.setEnd(w.jobEnd);
|
||||
apt.setTheme(BiomedAppointmentTheme.STYLES.get(w.color));
|
||||
|
||||
if (columnMap.containsKey(w.techId)) {
|
||||
apt.setColumnId(columnMap.get(w.techId));
|
||||
} else {
|
||||
columnId++;
|
||||
columnMap.put(w.techId, columnId);
|
||||
apt.setColumnId(columnId);
|
||||
}
|
||||
|
||||
calendar.addAppointment(apt);
|
||||
appointments.add(apt);
|
||||
@ -178,4 +203,8 @@ public class SchedulePanel extends Composite implements Schedule.View {
|
||||
|
||||
geocoder = Geocoder.create();
|
||||
}
|
||||
|
||||
public HasConstrainedValue<UserDTO> getTechField() {
|
||||
return techPicker;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,21 @@
|
||||
<ui:UiBinder
|
||||
xmlns:ui="urn:ui:com.google.gwt.uibinder"
|
||||
xmlns:g="urn:import:com.google.gwt.user.client.ui"
|
||||
xmlns:b="urn:import:com.github.gwtbootstrap.client.ui">
|
||||
|
||||
xmlns:b="urn:import:com.github.gwtbootstrap.client.ui"
|
||||
xmlns:dp="urn:import:com.google.gwt.user.datepicker.client">
|
||||
<g:HTMLPanel ui:field="rootPanel" styleName="scheduler">
|
||||
<div class="scheduler-head-bar" style="display: none">
|
||||
<b:Button size="MINI" type="PRIMARY">New Workorder</b:Button>
|
||||
<div class="item">
|
||||
<label>Date: </label>
|
||||
<dp:DateBox ui:field="datePicker"></dp:DateBox>
|
||||
</div>
|
||||
<div class="item">
|
||||
<label>Tech: </label>
|
||||
<b:ValueListBox ui:field="techPicker"></b:ValueListBox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<g:FlowPanel ui:field="mapContainer" />
|
||||
<g:FlowPanel ui:field="calContainer" />
|
||||
</g:HTMLPanel>
|
||||
|
@ -32,7 +32,8 @@ public class BiomedModule extends AbstractModule {
|
||||
private void bindProperties() {
|
||||
Properties prop = new Properties();
|
||||
try {
|
||||
prop.load(new FileInputStream("/srv/biomed/server.properties"));
|
||||
System.out.println("Current Directory: " + System.getProperty("user.dir"));
|
||||
prop.load(new FileInputStream("../server.properties"));
|
||||
Names.bindProperties(binder(), prop);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
|
@ -7,6 +7,7 @@ import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
import com.google.api.client.auth.oauth2.TokenResponse;
|
||||
import com.google.api.client.auth.oauth2.TokenResponseException;
|
||||
@ -27,121 +28,143 @@ import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
public class CalendarApi {
|
||||
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
|
||||
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
|
||||
private static final String CLIENT_ID = "333768673996-904fuljpb428q9r37m2uujislhal5kt9.apps.googleusercontent.com";
|
||||
private static final String CLIENT_SECRET = "PAmHruqVbAXzEnnTwelx-Ll7";
|
||||
private static final String REFRESH_TOKEN = "1/fWvZebnDAhY0MlgK1IImcrGIDm4ZlILiRM8_47HsUFc";
|
||||
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
|
||||
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
|
||||
private static final String CLIENT_ID = "333768673996-904fuljpb428q9r37m2uujislhal5kt9.apps.googleusercontent.com";
|
||||
private static final String CLIENT_SECRET = "PAmHruqVbAXzEnnTwelx-Ll7";
|
||||
private static final String REFRESH_TOKEN = "1/fWvZebnDAhY0MlgK1IImcrGIDm4ZlILiRM8_47HsUFc";
|
||||
|
||||
@Inject
|
||||
public CalendarApi() {
|
||||
}
|
||||
private final boolean devmode;
|
||||
|
||||
public String scheduleEvent(String email, Date startDate, Date endDate, String summary, String description, String location) {
|
||||
EventAttendee attendee = new EventAttendee();
|
||||
attendee.setEmail(email);
|
||||
@Inject
|
||||
public CalendarApi(@Named("devmode") boolean devmode) {
|
||||
this.devmode = devmode;
|
||||
}
|
||||
|
||||
Event event = new Event();
|
||||
event.setSummary(summary);
|
||||
event.setLocation(location);
|
||||
event.setDescription(description);
|
||||
public String scheduleEvent(String email, Date startDate, Date endDate,
|
||||
String summary, String description, String location) {
|
||||
if (devmode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<EventAttendee> attendees = Lists.newArrayList();
|
||||
attendees.add(attendee);
|
||||
event.setAttendees(attendees);
|
||||
EventAttendee attendee = new EventAttendee();
|
||||
attendee.setEmail(email);
|
||||
|
||||
DateTime start = new DateTime(startDate, TimeZone.getTimeZone("UTC"));
|
||||
event.setStart(new EventDateTime().setDateTime(start));
|
||||
DateTime end = new DateTime(endDate, TimeZone.getTimeZone("UTC"));
|
||||
event.setEnd(new EventDateTime().setDateTime(end));
|
||||
Event event = new Event();
|
||||
event.setSummary(summary);
|
||||
event.setLocation(location);
|
||||
event.setDescription(description);
|
||||
|
||||
Calendar calendar = buildCalendar();
|
||||
try {
|
||||
Event resultEvent = calendar.events().insert("api@atlanticbiomedical.com", event).execute();
|
||||
return resultEvent.getId();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
List<EventAttendee> attendees = Lists.newArrayList();
|
||||
attendees.add(attendee);
|
||||
event.setAttendees(attendees);
|
||||
|
||||
public void rescheduleEvent(String eventId, String email, Date startDate, Date endDate) {
|
||||
Calendar calendar = buildCalendar();
|
||||
DateTime start = new DateTime(startDate, TimeZone.getTimeZone("UTC"));
|
||||
event.setStart(new EventDateTime().setDateTime(start));
|
||||
DateTime end = new DateTime(endDate, TimeZone.getTimeZone("UTC"));
|
||||
event.setEnd(new EventDateTime().setDateTime(end));
|
||||
|
||||
try {
|
||||
Event event = calendar.events().get("api@atlanticbiomedical.com", eventId).execute();
|
||||
Calendar calendar = buildCalendar();
|
||||
try {
|
||||
Event resultEvent = calendar.events()
|
||||
.insert("api@atlanticbiomedical.com", event).execute();
|
||||
return resultEvent.getId();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
EventAttendee attendee = new EventAttendee();
|
||||
attendee.setEmail(email);
|
||||
List<EventAttendee> attendees = event.getAttendees();
|
||||
attendees.clear();
|
||||
attendees.add(attendee);
|
||||
public void rescheduleEvent(String eventId, String email, Date startDate,
|
||||
Date endDate) {
|
||||
if (devmode) {
|
||||
return;
|
||||
}
|
||||
|
||||
DateTime start = new DateTime(startDate, TimeZone.getTimeZone("UTC"));
|
||||
event.setStart(new EventDateTime().setDateTime(start));
|
||||
DateTime end = new DateTime(endDate, TimeZone.getTimeZone("UTC"));
|
||||
event.setEnd(new EventDateTime().setDateTime(end));
|
||||
Calendar calendar = buildCalendar();
|
||||
|
||||
calendar.events().update("api@atlanticbiomedical.com", eventId, event).execute();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
Event event = calendar.events()
|
||||
.get("api@atlanticbiomedical.com", eventId).execute();
|
||||
|
||||
public void deleteEvent(String eventId) {
|
||||
Calendar calendar = buildCalendar();
|
||||
EventAttendee attendee = new EventAttendee();
|
||||
attendee.setEmail(email);
|
||||
List<EventAttendee> attendees = event.getAttendees();
|
||||
attendees.clear();
|
||||
attendees.add(attendee);
|
||||
|
||||
try {
|
||||
calendar.events().delete("api@atlanticbiomedical.com", eventId).execute();
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
DateTime start = new DateTime(startDate, TimeZone.getTimeZone("UTC"));
|
||||
event.setStart(new EventDateTime().setDateTime(start));
|
||||
DateTime end = new DateTime(endDate, TimeZone.getTimeZone("UTC"));
|
||||
event.setEnd(new EventDateTime().setDateTime(end));
|
||||
|
||||
private static Map<String, String> buildCalendarMap() {
|
||||
Map<String, String> result = Maps.newHashMap();
|
||||
calendar.events().update("api@atlanticbiomedical.com", eventId, event)
|
||||
.execute();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Calendar calendar = buildCalendar();
|
||||
CalendarList feed = calendar.calendarList().list().execute();
|
||||
for (CalendarListEntry entry : feed.getItems()) {
|
||||
String summary = entry.getSummary();
|
||||
if (summary != null && summary.endsWith("atlanticbiomedical.com")) {
|
||||
result.put(summary, entry.getId());
|
||||
}
|
||||
public void deleteEvent(String eventId) {
|
||||
if (devmode) {
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("Found Calendar: " + summary + " -> " + entry.getId());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Calendar calendar = buildCalendar();
|
||||
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
calendar.events().delete("api@atlanticbiomedical.com", eventId).execute();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void test() throws IOException {
|
||||
Calendar calendar = buildCalendar();
|
||||
CalendarList feed = calendar.calendarList().list().execute();
|
||||
for (CalendarListEntry entry : feed.getItems()) {
|
||||
System.out.println(entry.getId());
|
||||
}
|
||||
}
|
||||
private static Map<String, String> buildCalendarMap() {
|
||||
Map<String, String> result = Maps.newHashMap();
|
||||
|
||||
private static Calendar buildCalendar() {
|
||||
try {
|
||||
GoogleCredential credential = new GoogleCredential().setAccessToken(getAccessToken());
|
||||
Calendar calendar = Calendar.builder(HTTP_TRANSPORT, JSON_FACTORY)
|
||||
.setApplicationName("BiomedPortal/1.0").setHttpRequestInitializer(credential).build();
|
||||
return calendar;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
Calendar calendar = buildCalendar();
|
||||
CalendarList feed = calendar.calendarList().list().execute();
|
||||
for (CalendarListEntry entry : feed.getItems()) {
|
||||
String summary = entry.getSummary();
|
||||
if (summary != null && summary.endsWith("atlanticbiomedical.com")) {
|
||||
result.put(summary, entry.getId());
|
||||
}
|
||||
|
||||
private static String getAccessToken() throws TokenResponseException, IOException {
|
||||
TokenResponse response = new GoogleRefreshTokenRequest(HTTP_TRANSPORT, JSON_FACTORY,
|
||||
REFRESH_TOKEN, CLIENT_ID, CLIENT_SECRET).execute();
|
||||
return response.getAccessToken();
|
||||
}
|
||||
System.out.println("Found Calendar: " + summary + " -> "
|
||||
+ entry.getId());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public void test() throws IOException {
|
||||
Calendar calendar = buildCalendar();
|
||||
CalendarList feed = calendar.calendarList().list().execute();
|
||||
for (CalendarListEntry entry : feed.getItems()) {
|
||||
System.out.println(entry.getId());
|
||||
}
|
||||
}
|
||||
|
||||
private static Calendar buildCalendar() {
|
||||
try {
|
||||
GoogleCredential credential = new GoogleCredential()
|
||||
.setAccessToken(getAccessToken());
|
||||
Calendar calendar = Calendar.builder(HTTP_TRANSPORT, JSON_FACTORY)
|
||||
.setApplicationName("BiomedPortal/1.0")
|
||||
.setHttpRequestInitializer(credential).build();
|
||||
return calendar;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getAccessToken() throws TokenResponseException,
|
||||
IOException {
|
||||
TokenResponse response = new GoogleRefreshTokenRequest(HTTP_TRANSPORT,
|
||||
JSON_FACTORY, REFRESH_TOKEN, CLIENT_ID, CLIENT_SECRET).execute();
|
||||
return response.getAccessToken();
|
||||
}
|
||||
}
|
||||
|
49
src/com/bradrydzewski/gwt/calendar/Calendar.gwt.xml
Normal file
49
src/com/bradrydzewski/gwt/calendar/Calendar.gwt.xml
Normal file
@ -0,0 +1,49 @@
|
||||
|
||||
<module>
|
||||
|
||||
<!-- Inherit the core Web Toolkit stuff -->
|
||||
<inherits name="com.google.gwt.user.User" />
|
||||
<inherits name="com.google.gwt.user.UserAgent"/>
|
||||
<inherits name='com.allen_sauer.gwt.dnd.gwt-dnd'/>
|
||||
<inherits name="com.google.gwt.i18n.I18N" />
|
||||
<extend-property name="locale" values="ar"/>
|
||||
<extend-property name="locale" values="bg"/>
|
||||
<extend-property name="locale" values="cs"/>
|
||||
<extend-property name="locale" values="da"/>
|
||||
<extend-property name="locale" values="de"/>
|
||||
<extend-property name="locale" values="es"/>
|
||||
<extend-property name="locale" values="es_MX"/>
|
||||
<extend-property name="locale" values="fi"/>
|
||||
<extend-property name="locale" values="fr"/>
|
||||
<extend-property name="locale" values="hu"/>
|
||||
<extend-property name="locale" values="it"/>
|
||||
<extend-property name="locale" values="ja"/>
|
||||
<extend-property name="locale" values="ko"/>
|
||||
<extend-property name="locale" values="nl"/>
|
||||
<extend-property name="locale" values="nn_NO"/>
|
||||
<extend-property name="locale" values="no"/>
|
||||
<extend-property name="locale" values="pl_PL"/>
|
||||
<extend-property name="locale" values="pl"/>
|
||||
<extend-property name="locale" values="pt_BR"/>
|
||||
<extend-property name="locale" values="ru"/>
|
||||
<extend-property name="locale" values="sk"/>
|
||||
<extend-property name="locale" values="sl"/>
|
||||
<extend-property name="locale" values="sv_SE"/>
|
||||
<extend-property name="locale" values="sv"/>
|
||||
<extend-property name="locale" values="tr"/>
|
||||
<extend-property name="locale" values="zh_CN"/>
|
||||
<extend-property name="locale" values="zh_TW"/>
|
||||
|
||||
<!-- Deferred Binding for better browser compatibility -->
|
||||
<replace-with class="com.bradrydzewski.gwt.calendar.client.util.impl.FormattingImpl">
|
||||
<when-type-is class="com.bradrydzewski.gwt.calendar.client.util.impl.FormattingImpl"/>
|
||||
</replace-with>
|
||||
<replace-with class="com.bradrydzewski.gwt.calendar.client.util.impl.FormattingIE6Impl">
|
||||
<when-type-is class="com.bradrydzewski.gwt.calendar.client.util.impl.FormattingImpl"/>
|
||||
<any>
|
||||
<when-property-is name="user.agent" value="ie6"/>
|
||||
<when-property-is name="user.agent" value="ie7"/>
|
||||
</any>
|
||||
</replace-with>
|
||||
|
||||
</module>
|
455
src/com/bradrydzewski/gwt/calendar/client/Appointment.java
Normal file
455
src/com/bradrydzewski/gwt/calendar/client/Appointment.java
Normal file
@ -0,0 +1,455 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010-2011 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.biomed.shared.api.dto.UserDTO;
|
||||
|
||||
/**
|
||||
* Represents an event that Calendar Views display and manipulate through the
|
||||
* gwt-cal provided user interface elements.
|
||||
* <p>
|
||||
* The <code>Appointment</code> class provides a set of text-based properties to
|
||||
* describe it, including a <em>title, description, location, createdBy</em>,
|
||||
* etc. Additional to these, there is a set of properties that exist to provide
|
||||
* the gwt-cal components with information useful during the
|
||||
* <code>Appointment</code> rendering in the widget views (<code>allDay</code>,
|
||||
* <code>recurring</code>, etc.)
|
||||
* </p>
|
||||
* <p>
|
||||
* All <code>Appointment</code> properties are ultimately used by the gwt-cal
|
||||
* views and it is up to these components to decide how to render (if at all)
|
||||
* them as well as to provide appropriate runtime features to modify them.
|
||||
* </p>
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class Appointment implements Comparable<Appointment>, Serializable {
|
||||
|
||||
private String id;
|
||||
private String title;
|
||||
private String description;
|
||||
private Date start;
|
||||
private Date end;
|
||||
private String location;
|
||||
private String createdBy;
|
||||
private List<Attendee> attendees = new ArrayList<Attendee>();
|
||||
private boolean allDay = false;
|
||||
private AppointmentStyle style = AppointmentStyle.DEFAULT;
|
||||
private String customStyle;
|
||||
private boolean readOnly = false;
|
||||
private int columnId;
|
||||
|
||||
public int getColumnId() {
|
||||
return columnId;
|
||||
}
|
||||
|
||||
public void setColumnId(int columnId) {
|
||||
this.columnId = columnId;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Creates an <code>Appointment</code> with the following attributes set to
|
||||
* <code>null</code>
|
||||
*
|
||||
* <ul>
|
||||
* <li><code>title</code></li>
|
||||
* <li><code>description</code></li>
|
||||
* <li><code>start</code></li>
|
||||
* <li><code>end</code></li>
|
||||
* <li><code><code>location</code></li>
|
||||
* <li><code>createdBy</code></li>
|
||||
* </ul>
|
||||
* the <code>attendees</code> collection empty the <code>allDay</code> and
|
||||
* the <code>readOnly</code> property <code>false</code>.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public Appointment() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the unique identifier for this <code>Appointment</code>. The
|
||||
* field is optional (and not used by gwt-cal) and therefore may be null.
|
||||
*
|
||||
* @return A unique identifier for this Appointment (optional).
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the unique identifier of this <code>Appointment</code>. This
|
||||
* identifier is optional.
|
||||
*
|
||||
* @param id Arbitrary string to uniquely identify the appointment.
|
||||
*/
|
||||
public void setId(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured start time-stamp of this <code>Appointment</code>.
|
||||
*
|
||||
* @return A date object with the date and time this appointment starts on
|
||||
*/
|
||||
public Date getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start time-stamp of this <code>Appointment</code>.
|
||||
*
|
||||
* @param start
|
||||
* A date object with the date and time this appointment starts
|
||||
*/
|
||||
public void setStart(final Date start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured end time-stamp of this <code>Appointment</code>.
|
||||
*
|
||||
* @return A date object with the date and time this appointment ends on
|
||||
*/
|
||||
public Date getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end time-stamp of this <code>Appointment</code>.
|
||||
*
|
||||
* @param end
|
||||
* A date object with the date and time this appointment ends on
|
||||
*/
|
||||
public void setEnd(final Date end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifying title of this <code>Appointment</code>.
|
||||
*
|
||||
* @return The title's short text
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the identifying title of this <code>Appointment</code>.
|
||||
*
|
||||
* @param title
|
||||
* The title's short text
|
||||
*/
|
||||
public void setTitle(final String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a description for this <code>Appointment</code>.
|
||||
*
|
||||
* @return The <code>appointment</code>'s description
|
||||
*/
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the description of this <code>Appointment</code>.
|
||||
*
|
||||
* @param description
|
||||
* The title's short text
|
||||
*/
|
||||
public void setDescription(final String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a location of this <code>Appointment</code>.
|
||||
*
|
||||
* @return The <code>appointment</code> location.
|
||||
*/
|
||||
public String getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the location of this <code>Appointment</code>.
|
||||
*
|
||||
* @param location
|
||||
* The <code>appointment</code> location
|
||||
*/
|
||||
public void setLocation(final String location) {
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a creator of this <code>Appointment</code>.
|
||||
*
|
||||
* @return The <code>appointment</code> creator description.
|
||||
*/
|
||||
public String getCreatedBy() {
|
||||
return createdBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the creator of this <code>Appointment</code>.
|
||||
*
|
||||
* @param createdBy
|
||||
* The <code>appointment</code> creator description.
|
||||
*/
|
||||
public void setCreatedBy(final String createdBy) {
|
||||
this.createdBy = createdBy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of associated attendees.
|
||||
*
|
||||
* @return The currently configured list of attendees
|
||||
*/
|
||||
public List<Attendee> getAttendees() {
|
||||
return attendees;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attendees associated to this <code>Appointment</code>.
|
||||
*
|
||||
* @param attendees
|
||||
* The entities associated (<em>attending</em>) this
|
||||
* <code>Appointment</code>
|
||||
*/
|
||||
public void setAttendees(final List<Attendee> attendees) {
|
||||
this.attendees = attendees;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this <code>Appointment</code> with the specified
|
||||
* <code>appointment</code> based first on the <code>start</code> dates of
|
||||
* each appointment and then (if they happen to be the same), on the
|
||||
* <code>end</code> dates.
|
||||
*
|
||||
* @param appointment
|
||||
* The appointment to compare this one to
|
||||
* @return a negative integer if <code>this</code> appointment
|
||||
* <em>is before</em> <code>appointment</code>, <code>zero</code> if
|
||||
* both appointments have the same <code>start</code>/
|
||||
* <code>end</code> dates, and a positive integer if
|
||||
* <code>this</code> appointment <em>is after</em>
|
||||
* <code>appointment</code>.
|
||||
*/
|
||||
public int compareTo(final Appointment appointment) {
|
||||
int compare = this.getStart().compareTo(appointment.getStart());
|
||||
|
||||
if (compare == 0) {
|
||||
compare = appointment.getEnd().compareTo(this.getEnd());
|
||||
}
|
||||
|
||||
return compare;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether this <code>Appointment</code> spans more than a single day,
|
||||
* based on its <code>start</code> and <code>end</code> properties.
|
||||
*
|
||||
* @return <code>true</code> if the <code>start</code> and <code>end</code>
|
||||
* dates fall on different dates, <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isMultiDay() {
|
||||
if (getEnd() != null && getStart() != null) {
|
||||
return !DateUtils.areOnTheSameDay(getEnd(), getStart());
|
||||
}
|
||||
throw new IllegalStateException(
|
||||
"Calculating isMultiDay with no start/end dates set");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured value of the <code>allDay</code> property, which
|
||||
* indicates if this <code>Appointment</code> should be considered as
|
||||
* spanning all day. It is left to the view rendering this
|
||||
* <code>Appointment</code> to decide how to render an appointment based on
|
||||
* this property value. For instance, the month view, will display the
|
||||
* <code>Appointment</code> at the top of the days in a week.
|
||||
*
|
||||
* @return The current value of the <code>allDay</code> property
|
||||
*/
|
||||
public boolean isAllDay() {
|
||||
return allDay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the the <code>allDay</code> property, which indicates if this
|
||||
* <code>Appointment</code> should be considered as spanning all day. It is
|
||||
* left to the view rendering this <code>Appointment</code> to decide how to
|
||||
* render an appointment based on this property value. For instance, the
|
||||
* month view, will display the <code>Appointment</code> at the top of the
|
||||
* days in a week.
|
||||
*
|
||||
* @param allDay
|
||||
* The current value of the <code>allDay</code> property
|
||||
*/
|
||||
public void setAllDay(final boolean allDay) {
|
||||
this.allDay = allDay;
|
||||
}
|
||||
|
||||
public AppointmentStyle getStyle() {
|
||||
return style;
|
||||
}
|
||||
|
||||
public void setStyle(final AppointmentStyle style) {
|
||||
this.style = style;
|
||||
}
|
||||
|
||||
public String getCustomStyle() {
|
||||
return customStyle;
|
||||
}
|
||||
|
||||
public void setCustomStyle(final String customStyle) {
|
||||
this.customStyle = customStyle;
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return readOnly;
|
||||
}
|
||||
|
||||
public void setReadOnly(final boolean readOnly) {
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
public Appointment clone() {
|
||||
Appointment clone = new Appointment();
|
||||
clone.setId(this.id);
|
||||
clone.setAllDay(this.allDay);
|
||||
clone.setAttendees(new ArrayList<Attendee>(this.attendees));
|
||||
clone.setCreatedBy(this.createdBy);
|
||||
clone.setDescription(this.description);
|
||||
clone.setEnd(DateUtils.newDate(this.end));
|
||||
clone.setLocation(this.location);
|
||||
clone.setStart(DateUtils.newDate(this.start));
|
||||
clone.setTitle(this.title);
|
||||
clone.setStyle(this.style);
|
||||
clone.setCustomStyle(this.customStyle);
|
||||
clone.setReadOnly(this.readOnly);
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((id == null) ? 0 : id.hashCode());
|
||||
result = prime * result + Boolean.valueOf(this.allDay).hashCode();
|
||||
result = prime * result + ((attendees == null) ? 0 : attendees.hashCode());
|
||||
result = prime * result + ((createdBy == null) ? 0 : createdBy.hashCode());
|
||||
result = prime * result + ((description == null) ? 0 : description.hashCode());
|
||||
result = prime * result + ((end == null) ? 0 : end.hashCode());
|
||||
result = prime * result + ((start == null) ? 0 : start.hashCode());
|
||||
result = prime * result + ((location == null) ? 0 : location.hashCode());
|
||||
result = prime * result + ((title == null) ? 0 : title.hashCode());
|
||||
result = prime * result + Boolean.valueOf(this.readOnly).hashCode();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof Appointment)) {
|
||||
return false;
|
||||
}
|
||||
Appointment other = (Appointment) obj;
|
||||
if (id == null) {
|
||||
if (other.id != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!id.equals(other.id)) {
|
||||
return false;
|
||||
}
|
||||
if (description == null) {
|
||||
if (other.description != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!description.equals(other.description)) {
|
||||
return false;
|
||||
}
|
||||
if (allDay != other.allDay) {
|
||||
return false;
|
||||
}
|
||||
if (attendees == null) {
|
||||
if (other.attendees != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!attendees.equals(other.attendees)) {
|
||||
return false;
|
||||
}
|
||||
if (createdBy == null) {
|
||||
if (other.createdBy != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!createdBy.equals(other.createdBy)) {
|
||||
return false;
|
||||
}
|
||||
if (end == null) {
|
||||
if (other.end != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!end.equals(other.end)) {
|
||||
return false;
|
||||
}
|
||||
if (start == null) {
|
||||
if (other.start != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!start.equals(other.start)) {
|
||||
return false;
|
||||
}
|
||||
if (location == null) {
|
||||
if (other.location != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!location.equals(other.location)) {
|
||||
return false;
|
||||
}
|
||||
if (title == null) {
|
||||
if (other.title != null) {
|
||||
return false;
|
||||
}
|
||||
} else if (!title.equals(other.title)) {
|
||||
return false;
|
||||
}
|
||||
if (readOnly != other.readOnly) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,355 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Manages operations and state for the entire set of appointments displayed by
|
||||
* the GWT calendar. <p></p>
|
||||
* <p/>
|
||||
* The key responsibilities of the <code>AppointmentManager</code> are: <ul>
|
||||
* <li>Keep the calendar collection of appointments and provide operations to
|
||||
* update it</li> <li>Identify one of the appointments as the "currently
|
||||
* selected"</li> <li>Provide "navigation" methods to move the
|
||||
* "currently selected" from appointment to appointment over the
|
||||
* collection</li> <li>Keep track of changes to the set of appointments to
|
||||
* identify when sorting of the appointments -if client code needs them
|
||||
* chronologically ordered- should take place, i.e. appointments are not
|
||||
* guaranteed to be always in chronological order</li> </ul>
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class AppointmentManager {
|
||||
/**
|
||||
* A reference to the "currently selected appointment". Will be
|
||||
* <code>null</code> when no currently selected appointment has been set.
|
||||
*/
|
||||
private Appointment selectedAppointment = null;
|
||||
|
||||
/**
|
||||
* A reference to the most recent appointment to receive
|
||||
* a mouse over event.
|
||||
*/
|
||||
private Appointment hoveredAppointment = null;
|
||||
|
||||
/**
|
||||
* A copy of the last appointment that was updated,
|
||||
* prior to the update taking place.
|
||||
*/
|
||||
private Appointment rollbackAppointment = null;
|
||||
|
||||
/**
|
||||
* A reference to the last appointment that was updated.
|
||||
*/
|
||||
private Appointment committedAppointment = null;
|
||||
|
||||
/**
|
||||
* The collection of appointments to be maintained by this
|
||||
* <code>AppointmentManager</code>.
|
||||
*/
|
||||
private ArrayList<Appointment> appointments = new ArrayList<Appointment>();
|
||||
|
||||
/**
|
||||
* Internal state flag indicating whether the collection of appointments
|
||||
* needs to be sorted.
|
||||
*/
|
||||
private boolean sortPending = true;
|
||||
|
||||
/**
|
||||
* Returns the collection of appointments that this <code>AppointmentManager</code>
|
||||
* maintains. <strong>Warning</strong>: this method returns a modifiable
|
||||
* reference to the internally managed list of appointments; client code
|
||||
* might break the invariants that this <code>AppointmentManager</code>
|
||||
* enforces if it performs any operations that modify the returned
|
||||
* collection.
|
||||
*
|
||||
* @return The appointments managed by this <code>AppointmentManager</code>.
|
||||
*/
|
||||
public List<Appointment> getAppointments() {
|
||||
return appointments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an appointment to the collection of appointments maintained by this
|
||||
* <code>ApplicationManager</code>.
|
||||
*
|
||||
* @param appt The appointment to be made part of this manager's managed
|
||||
* collection
|
||||
*/
|
||||
public void addAppointment(Appointment appt) {
|
||||
if (appt != null) {
|
||||
appointments.add(appt);
|
||||
sortPending = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds multiple appointments to the collection maintained by this
|
||||
* <code>ApplicationManager</code>.
|
||||
*
|
||||
* @param appointments The appointments that will be made part of this
|
||||
* manager's managed collection
|
||||
*/
|
||||
public void addAppointments(List<Appointment> appointments) {
|
||||
if (appointments != null) {
|
||||
for (Appointment appointment : appointments) {
|
||||
addAppointment(appointment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the <code>appointment</code> from this manager's managed
|
||||
* collection.
|
||||
*
|
||||
* @param appointment The appointment to remove
|
||||
*/
|
||||
public void removeAppointment(Appointment appointment) {
|
||||
if (appointment != null) {
|
||||
boolean wasRemoved = appointments.remove(appointment);
|
||||
if (wasRemoved) {
|
||||
sortPending = true;
|
||||
}
|
||||
//I'd rather have the client keep the reference to the selected one if they need it than having here
|
||||
//a reference to a thing I no longer should know about...
|
||||
if (hasAppointmentSelected() &&
|
||||
getSelectedAppointment().equals(appointment)) {
|
||||
selectedAppointment = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the "currently selected" appointment from this
|
||||
* manager's collection.
|
||||
*/
|
||||
public void removeCurrentlySelectedAppointment() {
|
||||
if (hasAppointmentSelected()) {
|
||||
removeAppointment(getSelectedAppointment());
|
||||
selectedAppointment = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Empties the collection of managed appointments.
|
||||
*/
|
||||
public void clearAppointments() {
|
||||
appointments.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the appointment that should be considered the "currently
|
||||
* selected" appointment.
|
||||
*
|
||||
* @param selectedAppointment The appointment to consider "currently
|
||||
* selected"
|
||||
*/
|
||||
public void setSelectedAppointment(Appointment selectedAppointment) {
|
||||
if (selectedAppointment != null &&
|
||||
appointments.contains(selectedAppointment)) {
|
||||
this.selectedAppointment = selectedAppointment;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether there is a "currently selected" appointment
|
||||
* at the moment.
|
||||
*
|
||||
* @return <code>true</code> if there is a currently selected appointment
|
||||
* for the collection managed by this component, <code>false</code>
|
||||
* otherwise
|
||||
*/
|
||||
public boolean hasAppointmentSelected() {
|
||||
return selectedAppointment != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the appointment in this manager's collection that is
|
||||
* "currently selected".
|
||||
*
|
||||
* @return The currently selected appointment
|
||||
*/
|
||||
public Appointment getSelectedAppointment() {
|
||||
return selectedAppointment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts the collection of appointments by their natural order.
|
||||
*/
|
||||
public void sortAppointments() {
|
||||
if (sortPending) {
|
||||
Collections.sort(appointments);
|
||||
sortPending = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the "currently selected" to the previous appointment in
|
||||
* the managed collection of this <code>AppointmentManager</code>. <br/> The
|
||||
* "previous" appointment will be the appointment before the
|
||||
* currently selected appointment in the set of appointments (whether
|
||||
* ordered or not).
|
||||
* <p/>
|
||||
* <br/> Because this operation depends on a "currently selected
|
||||
* appointment", no previous appointment is considered to exist if
|
||||
* there is no "currently selected appointment." or it is the
|
||||
* first in the set.
|
||||
*
|
||||
* @return <code>true</code> if selecting the previous appointment was
|
||||
* successful, <code>false</code> no currently selected appointment
|
||||
* is set or the currently selected appointment is the first in the
|
||||
* collection.
|
||||
*/
|
||||
public boolean selectPreviousAppointment() {
|
||||
boolean moveSucceeded = false;
|
||||
if (getSelectedAppointment() != null) {
|
||||
int selectedApptIndex =
|
||||
getAppointments().indexOf(getSelectedAppointment());
|
||||
Appointment prevAppt;
|
||||
if (selectedApptIndex > 0 && (prevAppt =
|
||||
getAppointments().get(selectedApptIndex - 1)) != null) {
|
||||
selectedAppointment = prevAppt;
|
||||
moveSucceeded = true;
|
||||
}
|
||||
}
|
||||
return moveSucceeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the "currently selected" to the next appointment in the
|
||||
* managed collection of this <code>AppointmentManager</code>. <br/> The
|
||||
* "next" appointment will be the appointment after the currently
|
||||
* selected appointment in the set of appointments (whether ordered or
|
||||
* not).
|
||||
* <p/>
|
||||
* <br/> Because this operation depends on a "currently selected
|
||||
* appointment", no next appointment is considered to exist if there is
|
||||
* no "currently selected appointment or it is the last in the
|
||||
* set."
|
||||
*
|
||||
* @return <code>true</code> if selecting the previous appointment was
|
||||
* successful, <code>false</code> no currently selected appointment
|
||||
* is set or the currently selected appointment is the last in the
|
||||
* collection.
|
||||
*/
|
||||
public boolean selectNextAppointment() {
|
||||
boolean moveSucceeded = false;
|
||||
|
||||
if (getSelectedAppointment() != null) {
|
||||
int selectedApptIndex =
|
||||
getAppointments().indexOf(getSelectedAppointment());
|
||||
int lastIndex = getAppointments().size() - 1;
|
||||
|
||||
Appointment nextAppt;
|
||||
if (selectedApptIndex < lastIndex
|
||||
&& (nextAppt = getAppointments().get(selectedApptIndex + 1)) != null) {
|
||||
selectedAppointment = nextAppt;
|
||||
moveSucceeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
return moveSucceeded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the "currently selected" appointment of this manager.
|
||||
* <p></p>If this manager has a currently selected appointment, the
|
||||
* appointment <code>selected</code> property will be set to
|
||||
* <code>false</code> and this manager's <code>selectedAppointment</code>
|
||||
* property will be set to <code>null</code>.
|
||||
*/
|
||||
public void resetSelectedAppointment() {
|
||||
if (hasAppointmentSelected()) {
|
||||
//selectedAppointment.setSelected(false);
|
||||
selectedAppointment = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the passed <code>appointment</code> is the same one as the
|
||||
* one that is currently selected in this manager.
|
||||
*
|
||||
* @param appointment The appointment to test to be the same as the
|
||||
* currently selected
|
||||
* @return <code>true</code> if there is a currently selected appointment
|
||||
* and it is equal to the passed <code>appointment</code>
|
||||
*/
|
||||
public boolean isTheSelectedAppointment(Appointment appointment) {
|
||||
return hasAppointmentSelected() && selectedAppointment.equals(
|
||||
appointment);
|
||||
}
|
||||
|
||||
public void commit() {
|
||||
rollbackAppointment = null;
|
||||
committedAppointment = null;
|
||||
}
|
||||
|
||||
public void rollback() {
|
||||
|
||||
//if the snapshot block is empty, we can do nothing
|
||||
if(rollbackAppointment==null && committedAppointment==null)
|
||||
return;
|
||||
|
||||
//if there is no committed appointment, we assume
|
||||
// this was a delete operation. We re-add the appointment
|
||||
if (committedAppointment == null) {
|
||||
addAppointment(rollbackAppointment);
|
||||
|
||||
//if there is no rollback appointment, we assume
|
||||
// this was an add or update operation. We remove the appointment
|
||||
} else if (rollbackAppointment == null) {
|
||||
removeAppointment(committedAppointment);
|
||||
|
||||
//else, we assume this is an update
|
||||
} else {
|
||||
|
||||
removeAppointment(committedAppointment);
|
||||
addAppointment(rollbackAppointment);
|
||||
}
|
||||
|
||||
commit();
|
||||
}
|
||||
|
||||
public void setRollbackAppointment(Appointment appt) {
|
||||
sortPending = true;
|
||||
commit();
|
||||
rollbackAppointment = appt;
|
||||
}
|
||||
|
||||
public void setCommittedAppointment(Appointment appt) {
|
||||
sortPending = true;
|
||||
committedAppointment = appt;
|
||||
}
|
||||
|
||||
public void resetHoveredAppointment() {
|
||||
this.hoveredAppointment = null;
|
||||
}
|
||||
|
||||
public void setHoveredAppointment(Appointment hoveredAppointment) {
|
||||
this.hoveredAppointment = hoveredAppointment;
|
||||
}
|
||||
|
||||
public Appointment getHoveredAppointment() {
|
||||
return hoveredAppointment;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
||||
|
||||
public enum AppointmentStyle implements Serializable, IsSerializable {
|
||||
BLUE, RED, PINK, PURPLE, DARK_PURPLE, STEELE_BLUE, LIGHT_BLUE,
|
||||
TEAL, LIGHT_TEAL, GREEN, LIGHT_GREEN, YELLOW_GREEN, YELLOW,
|
||||
ORANGE, RED_ORANGE, LIGHT_BROWN, LIGHT_PURPLE, GREY, BLUE_GREY,
|
||||
YELLOW_GREY, BROWN, DEFAULT, CUSTOM
|
||||
}
|
150
src/com/bradrydzewski/gwt/calendar/client/Attendee.java
Normal file
150
src/com/bradrydzewski/gwt/calendar/client/Attendee.java
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* A simple JavaBean class representing an entity associated to an appointment,
|
||||
* most likely a person, but might as well be a resource (like a conference room or a
|
||||
* projector).
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class Attendee implements Serializable {
|
||||
|
||||
/**
|
||||
* The <code>Attendee</code> id. This field can be used to relate the Attendee with some
|
||||
* external source (contact, resource, ....)
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* The <code>Attendee</code> name (if a person) or description
|
||||
* (when a resource).
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* This <code>Attendee</code> email address.
|
||||
*/
|
||||
private String email;
|
||||
|
||||
/**
|
||||
* The status of attendance of this attendee to an <code>Appointment</code>.
|
||||
*/
|
||||
private Attending attending = Attending.Maybe;
|
||||
|
||||
/**
|
||||
* A URL to an image to depict this <code>Attendee</code>.
|
||||
*/
|
||||
private String imageUrl;
|
||||
|
||||
/**
|
||||
* Returns the name (if a person) or description (when a resource)
|
||||
* of this <code>Attendee</code>.
|
||||
*
|
||||
* @return The currently configured name of this attendee
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name (if a person) or description (when a resource)
|
||||
* of this <code>Attendee</code>.
|
||||
*
|
||||
* @param name The name of this attendee
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns this <code>Attendee</code> email address.
|
||||
*
|
||||
* @return The email address
|
||||
*/
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this <code>Attendee</code> email address.
|
||||
* @param email The email address
|
||||
*/
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attendance status of <code>this</code> attendant
|
||||
* to the <code>Appointment</code> referencing it.
|
||||
* @return The attendance status of this <code>Attendee</code>
|
||||
*/
|
||||
public Attending getAttending() {
|
||||
return attending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attendance status of <code>this</code> attendant
|
||||
* to the <code>Appointment</code> referencing it.
|
||||
*
|
||||
* @param attending The attendance status
|
||||
*/
|
||||
public void setAttending(Attending attending) {
|
||||
this.attending = attending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the URL to an image to (optionally) depict this <code>Attendee</code>
|
||||
* in the views.
|
||||
* @return A URL (relative or absolute) meaningful within the
|
||||
* deployed application context
|
||||
*/
|
||||
public String getImageUrl() {
|
||||
return imageUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the URL to an image to (optionally) depict this <code>Attendee</code>
|
||||
* in the views.
|
||||
* @param imageUrl A URL (relative or absolute) meaningful within the
|
||||
*/
|
||||
public void setImageUrl(String imageUrl) {
|
||||
this.imageUrl = imageUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the attendance ID.
|
||||
* @return The attendance ID
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the attendance the ID.
|
||||
* @param id The ID
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
46
src/com/bradrydzewski/gwt/calendar/client/Attending.java
Normal file
46
src/com/bradrydzewski/gwt/calendar/client/Attending.java
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import com.google.gwt.user.client.rpc.IsSerializable;
|
||||
|
||||
/**
|
||||
* Indicates whether or not an Attendee will be attending an
|
||||
* {@link Appointment}.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @since 0.9.0
|
||||
*/
|
||||
public enum Attending implements Serializable, IsSerializable {
|
||||
/**
|
||||
* Indicates an Attendee will be attending.
|
||||
*/
|
||||
Yes,
|
||||
/**
|
||||
* Indicates an Attendee will not be attending.
|
||||
*/
|
||||
No,
|
||||
/**
|
||||
* Indicates an Attendee has not yet made up their mind
|
||||
* whether or not they will be attending.
|
||||
*/
|
||||
Maybe
|
||||
}
|
163
src/com/bradrydzewski/gwt/calendar/client/Calendar.java
Normal file
163
src/com/bradrydzewski/gwt/calendar/client/Calendar.java
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.dayview.DayView;
|
||||
import com.bradrydzewski.gwt.calendar.client.monthview.MonthView;
|
||||
import com.bradrydzewski.gwt.calendar.client.techview.TechView;
|
||||
import com.google.gwt.user.client.Timer;
|
||||
import com.google.gwt.user.client.ui.ProvidesResize;
|
||||
import com.google.gwt.user.client.ui.RequiresResize;
|
||||
|
||||
public class Calendar extends CalendarWidget implements RequiresResize,
|
||||
ProvidesResize {
|
||||
|
||||
/**
|
||||
* The component to manage the presentation of appointments in a single day
|
||||
* layout.
|
||||
*/
|
||||
private DayView dayView = null;
|
||||
|
||||
/**
|
||||
* The component to manage the presentation of appointments in a month.
|
||||
*/
|
||||
private MonthView monthView = null;
|
||||
|
||||
private TechView techView = null;
|
||||
|
||||
private CalendarViews selectedView = null;
|
||||
|
||||
/**
|
||||
* Constructs a <code>Calendar</code> with the DayView currently displayed.
|
||||
*/
|
||||
public Calendar() {
|
||||
this(CalendarViews.DAY, CalendarSettings.DEFAULT_SETTINGS);
|
||||
}
|
||||
|
||||
public Calendar(CalendarSettings settings) {
|
||||
this(CalendarViews.DAY, settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>Calendar</code> with the given CalendarView displayed by
|
||||
* default.
|
||||
*/
|
||||
public Calendar(CalendarViews view, CalendarSettings settings) {
|
||||
super();
|
||||
this.setSettings(settings);
|
||||
setView(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>Calendar</code> with the a user-defined CalendarView
|
||||
* displayed by default.
|
||||
*/
|
||||
public Calendar(CalendarView view) {
|
||||
super();
|
||||
setView(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the CalendarView that should be used by the Calendar to display the
|
||||
* list of appointments.
|
||||
*
|
||||
* @param view
|
||||
*/
|
||||
final public void setView(CalendarViews view) {
|
||||
setView(view, getDays());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current view of this calendar.
|
||||
*
|
||||
* @param view
|
||||
* The ID of a view used to visualize the appointments managed by the
|
||||
* calendar
|
||||
* @param days
|
||||
* The number of days to display in the view, which can be ignored by
|
||||
* some views.
|
||||
*/
|
||||
public void setView(CalendarViews view, int days) {
|
||||
switch (view) {
|
||||
case DAY: {
|
||||
if (dayView == null) {
|
||||
dayView = new DayView();
|
||||
}
|
||||
dayView.setDisplayedDays(days);
|
||||
setView(dayView);
|
||||
break;
|
||||
}
|
||||
case AGENDA: {
|
||||
// TODO: need to cache agendaView, but there is a layout bug after a
|
||||
// calendar item is deleted.
|
||||
// agendaView = new AgendaView();
|
||||
// setView(agendaView);
|
||||
// break;
|
||||
throw new RuntimeException("Agenda View is not yet supported");
|
||||
}
|
||||
case MONTH: {
|
||||
if (monthView == null) {
|
||||
monthView = new MonthView();
|
||||
}
|
||||
setView(monthView);
|
||||
break;
|
||||
}
|
||||
case TECH: {
|
||||
if (techView == null) {
|
||||
techView = new TechView();
|
||||
}
|
||||
setView(techView);
|
||||
break;
|
||||
}
|
||||
}
|
||||
selectedView = view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current view of this calendar.
|
||||
*
|
||||
* @return Current view
|
||||
*/
|
||||
public CalendarViews getCalendarView() {
|
||||
return selectedView;
|
||||
}
|
||||
|
||||
public void onResize() {
|
||||
resizeTimer.schedule(500);
|
||||
}
|
||||
|
||||
private Timer resizeTimer = new Timer() {
|
||||
/**
|
||||
* Snapshot of the Calendar's height at the last time it was resized.
|
||||
*/
|
||||
private int height;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
int newHeight = getOffsetHeight();
|
||||
if (newHeight != height) {
|
||||
height = newHeight;
|
||||
doSizing();
|
||||
if (getView() instanceof MonthView)
|
||||
doLayout();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
312
src/com/bradrydzewski/gwt/calendar/client/CalendarFormat.java
Normal file
312
src/com/bradrydzewski/gwt/calendar/client/CalendarFormat.java
Normal file
@ -0,0 +1,312 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009-2011 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.i18n.CalendarConstants;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
final public class CalendarFormat {
|
||||
|
||||
public static final CalendarConstants MESSAGES =
|
||||
(CalendarConstants) GWT.create(CalendarConstants.class);
|
||||
|
||||
public static final int HOURS_IN_DAY = 24;
|
||||
|
||||
private static final DateTimeFormat DEFAULT_DAY_OF_MONTH_FORMAT =
|
||||
DateTimeFormat.getFormat(MESSAGES.dayOfMonthFormat());
|
||||
|
||||
private static final DateTimeFormat DEFAULT_DAY_OF_WEEK_FORMAT =
|
||||
DateTimeFormat.getFormat(MESSAGES.weekdayFormat());
|
||||
|
||||
private static final DateTimeFormat DEFAULT_DAY_OF_WEEK_ABBREVIATED_FORMAT =
|
||||
DateTimeFormat.getFormat(MESSAGES.weekdayFormat());
|
||||
|
||||
private static final DateTimeFormat DEFAULT_HOUR_FORMAT =
|
||||
DateTimeFormat.getFormat(MESSAGES.timeFormat());
|
||||
|
||||
private static final DateTimeFormat DEFAULT_DATE_FORMAT =
|
||||
DateTimeFormat.getFormat(MESSAGES.dateFormat());
|
||||
|
||||
private static String DEFAULT_AM_LABEL = MESSAGES.am();
|
||||
private static String DEFAULT_PM_LABEL = MESSAGES.pm();
|
||||
private static String DEFAULT_NOON_LABEL = MESSAGES.noon();
|
||||
|
||||
private String[] weekDayNames = new String[7];
|
||||
private String[] dayOfWeekAbbreviatedNames = new String[7];
|
||||
private String[] dayOfMonthNames = new String[32];
|
||||
private String[] hours = new String[24];
|
||||
|
||||
private DateTimeFormat dayOfMonthFormat = null;
|
||||
private DateTimeFormat dayOfWeekFormat = null;
|
||||
private DateTimeFormat dayOfWeekAbbreviatedFormat = null;
|
||||
private DateTimeFormat timeFormat = null;
|
||||
private DateTimeFormat dateFormat = null;
|
||||
private String am = null;
|
||||
private String pm = null;
|
||||
private String noon = null;
|
||||
|
||||
private boolean useNoonLabel = true;
|
||||
|
||||
private int firstDayOfWeek = Integer.valueOf(MESSAGES.firstDayOfWeek());
|
||||
|
||||
public static CalendarFormat INSTANCE = new CalendarFormat();
|
||||
|
||||
private CalendarFormat() {
|
||||
dayOfMonthFormat = DEFAULT_DAY_OF_MONTH_FORMAT;
|
||||
dayOfWeekFormat = DEFAULT_DAY_OF_WEEK_FORMAT;
|
||||
dayOfWeekAbbreviatedFormat = DEFAULT_DAY_OF_WEEK_ABBREVIATED_FORMAT;
|
||||
timeFormat = DEFAULT_HOUR_FORMAT;
|
||||
dateFormat = DEFAULT_DATE_FORMAT;
|
||||
am = DEFAULT_AM_LABEL;
|
||||
pm = DEFAULT_PM_LABEL;
|
||||
noon = DEFAULT_NOON_LABEL;
|
||||
refreshWeekDayNames();
|
||||
refreshMonthDayNames();
|
||||
generateHourLabels();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the formatting pattern to render the days of the week using
|
||||
* <code>DateTimeFormat</code>.
|
||||
*
|
||||
* @param formatPattern The pattern to format day names
|
||||
* @see com.google.gwt.i18n.client.DateTimeFormat#getFormat(String)
|
||||
*/
|
||||
public void setDayOfWeekFormat(String formatPattern) {
|
||||
dayOfWeekFormat = DateTimeFormat.getFormat(formatPattern);
|
||||
refreshWeekDayNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the names (labels) of the days of the week.
|
||||
*
|
||||
* @return The days of the 7 days of the week, formatted with the current
|
||||
* configuration
|
||||
*/
|
||||
public String[] getDayOfWeekNames() {
|
||||
return weekDayNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the formatting pattern to render the days of the week in an
|
||||
* abbreviated manner using <code>DateTimeFormat</code>.
|
||||
*
|
||||
* @param formatPattern The pattern to format day names
|
||||
* @see com.google.gwt.i18n.client.DateTimeFormat#getFormat(String)
|
||||
*/
|
||||
public void setDayOfWeekAbbreviatedFormat(String formatPattern) {
|
||||
dayOfWeekAbbreviatedFormat = DateTimeFormat.getFormat(formatPattern);
|
||||
refreshWeekDayNames();
|
||||
}
|
||||
|
||||
public String[] getDayOfWeekAbbreviatedNames() {
|
||||
return dayOfWeekAbbreviatedNames;
|
||||
}
|
||||
|
||||
private void refreshWeekDayNames() {
|
||||
Date date = new Date();
|
||||
for (int i = 1; i <= 7; i++) {
|
||||
date.setDate(i);
|
||||
int dayOfWeek = date.getDay();
|
||||
weekDayNames[dayOfWeek] = dayOfWeekFormat.format(date);
|
||||
dayOfWeekAbbreviatedNames[dayOfWeek] =
|
||||
dayOfWeekAbbreviatedFormat.format(date);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the formatting pattern to render the days of the month using
|
||||
* <code>DateTimeFormat</code>. Most likely, <code>formatPattern</code> will
|
||||
* contain at the minimum, the format to render the number of the
|
||||
* corresponding day.
|
||||
*
|
||||
* @param formatPattern The pattern to format days in the month view
|
||||
* @see com.google.gwt.i18n.client.DateTimeFormat#getFormat(String)
|
||||
*/
|
||||
public void setDayOfMonthFormat(String formatPattern) {
|
||||
dayOfMonthFormat = DateTimeFormat.getFormat(formatPattern);
|
||||
refreshMonthDayNames();
|
||||
}
|
||||
|
||||
private void refreshMonthDayNames() {
|
||||
Date date = new Date();
|
||||
date.setMonth(0);
|
||||
for (int i = 1; i < 32; ++i) {
|
||||
date.setDate(i);
|
||||
dayOfMonthNames[i] = dayOfMonthFormat.format(date);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDateFormat(String formatPattern) {
|
||||
dateFormat = DateTimeFormat.getFormat(formatPattern);
|
||||
}
|
||||
|
||||
public DateTimeFormat getDateFormat() {
|
||||
return dateFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pattern used to format the displayed hours and re-generates
|
||||
* all hour labels.
|
||||
*
|
||||
* @param formatPattern A legal format following the patterns
|
||||
* in {@link com.google.gwt.i18n.client.DateTimeFormat}
|
||||
*/
|
||||
public void setTimeFormat(String formatPattern) {
|
||||
timeFormat = DateTimeFormat.getFormat(formatPattern);
|
||||
generateHourLabels();
|
||||
}
|
||||
|
||||
public DateTimeFormat getTimeFormat() {
|
||||
return timeFormat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows programmatic configuration of the 24 hour labels in the calendar.
|
||||
*
|
||||
* @param hourLabels The labels to be used as labels for the hours of the
|
||||
* day.
|
||||
* @throws IllegalArgumentException If the <code>hourLabels</code> array is
|
||||
* <code>null</code>, does not have 24
|
||||
* elements, or any of the elements is
|
||||
* <code>null</code>
|
||||
*/
|
||||
public void setHourLabels(String[] hourLabels) {
|
||||
if (hourLabels == null || hourLabels.length != HOURS_IN_DAY) {
|
||||
throw new IllegalArgumentException(
|
||||
"24 Hour labels expected. Please provide an array with 24 non-null values");
|
||||
}
|
||||
for (int i = 0; i < HOURS_IN_DAY; i++) {
|
||||
if (hourLabels[i] == null) {
|
||||
throw new IllegalArgumentException(
|
||||
"Hour @ position " + i + " is null.");
|
||||
}
|
||||
hours[i] = hourLabels[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default logic to generate the labels for the hours.
|
||||
*/
|
||||
private void generateHourLabels() {
|
||||
Date date = new Date();
|
||||
date.setHours(0);
|
||||
date.setMinutes(0);
|
||||
String hour;
|
||||
|
||||
for (int i = 0; i < HOURS_IN_DAY; i++) {
|
||||
date.setHours(i);
|
||||
hour = timeFormat.format(date);
|
||||
//shortTimeFormat.format(date);
|
||||
hours[i] = hour;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently configured day to start weeks in the
|
||||
* <code>MonthView</code>. The default value is read from the
|
||||
* <code>CalendarConstants</code> i18n configuration file, but it can be
|
||||
* changed through the <code>setFirstDayOfWeek</code> method of this class.
|
||||
*
|
||||
* @return The currently configured day to start weeks, <code>0</code> for
|
||||
* Sunday, <code>1</code> for Monday, and so on.
|
||||
*/
|
||||
public int getFirstDayOfWeek() {
|
||||
return firstDayOfWeek;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the first day in the week when rendering the month view.
|
||||
*
|
||||
* @param firstDayOfWeek The first day of the week, where Sunday is
|
||||
* represented by <code>0</code>, Monday by
|
||||
* <code>1</code>, and so on.
|
||||
*/
|
||||
public void setFirstDayOfWeek(int firstDayOfWeek) {
|
||||
this.firstDayOfWeek = Math.abs(firstDayOfWeek % 7);
|
||||
}
|
||||
|
||||
public String getAm() {
|
||||
return am;
|
||||
}
|
||||
|
||||
public void setAm(String am) {
|
||||
this.am = am;
|
||||
}
|
||||
|
||||
public String getPm() {
|
||||
return pm;
|
||||
}
|
||||
|
||||
public void setPm(String pm) {
|
||||
this.pm = pm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently configured label for the noon (12 p.m.).
|
||||
*
|
||||
* @return The configured label for the 12 p.m. time either through the
|
||||
* <code>CalendarConstants</code> or the <code>setNoon</code> method
|
||||
* of this class.
|
||||
*/
|
||||
public String getNoon() {
|
||||
return noon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the label to show for the 12 p.m.
|
||||
*
|
||||
* @param noon A label to show instead of 12 p.m.
|
||||
*/
|
||||
public void setNoon(String noon) {
|
||||
this.noon = noon;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the configured labels for the 24 hours of the day. Some labels
|
||||
* will vary, depending con configuration, for example "Noon"
|
||||
* instead of "12".
|
||||
*
|
||||
* @return An array of Strings with the corresponding labels for the hours in
|
||||
* a day
|
||||
*/
|
||||
public String[] getHourLabels() {
|
||||
return hours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if we want to use the NoonLabel or the 12 p.m.
|
||||
* @param use <code>true</true> if we want to use the NoonLabel, <code>false</true> otherwise
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public void setUseNoonLabel(boolean use) {
|
||||
this.useNoonLabel = use;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if we are using the NoonLabel for the 12 p.m.
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public boolean isUseNoonLabel() {
|
||||
return useNoonLabel;
|
||||
}
|
||||
}
|
182
src/com/bradrydzewski/gwt/calendar/client/CalendarSettings.java
Normal file
182
src/com/bradrydzewski/gwt/calendar/client/CalendarSettings.java
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Brad Rydzewski
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class CalendarSettings {
|
||||
|
||||
public static CalendarSettings DEFAULT_SETTINGS = new CalendarSettings();
|
||||
|
||||
private int pixelsPerInterval = 30; //IE6 cannot be less than 20!!!!!
|
||||
private int intervalsPerHour = 2;
|
||||
private int workingHourStart = 8;
|
||||
private int workingHourEnd = 17;
|
||||
private int scrollToHour = 8; //default hour that gets scrolled to
|
||||
private boolean enableDragDrop = true;
|
||||
private boolean offsetHourLabels = false;
|
||||
private boolean showWeekNumbers = false;
|
||||
private boolean showMultiDay = true;
|
||||
private List<Date> holidays = new ArrayList<Date>();
|
||||
private int dayStartsAt = 0;
|
||||
|
||||
/*
|
||||
* Clicks required to fire TimeBlockClickEvent.
|
||||
*/
|
||||
private Click timeBlockClickNumber = Click.Single;
|
||||
|
||||
public CalendarSettings() {
|
||||
}
|
||||
|
||||
public int getPixelsPerInterval() {
|
||||
return pixelsPerInterval;
|
||||
}
|
||||
|
||||
public void setPixelsPerInterval(final int px) {
|
||||
pixelsPerInterval = px;
|
||||
}
|
||||
|
||||
public int getIntervalsPerHour() {
|
||||
return intervalsPerHour;
|
||||
}
|
||||
|
||||
public void setIntervalsPerHour(final int intervals) {
|
||||
intervalsPerHour = intervals;
|
||||
}
|
||||
|
||||
public int getWorkingHourStart() {
|
||||
return workingHourStart;
|
||||
}
|
||||
|
||||
public void setWorkingHourStart(final int start) {
|
||||
workingHourStart = start;
|
||||
}
|
||||
|
||||
public int getWorkingHourEnd() {
|
||||
return workingHourEnd;
|
||||
}
|
||||
|
||||
public void setWorkingHourEnd(final int end) {
|
||||
workingHourEnd = end;
|
||||
}
|
||||
|
||||
public int getScrollToHour() {
|
||||
return scrollToHour;
|
||||
}
|
||||
|
||||
public void setScrollToHour(final int hour) {
|
||||
scrollToHour = hour;
|
||||
}
|
||||
|
||||
public boolean isEnableDragDrop() {
|
||||
return enableDragDrop;
|
||||
}
|
||||
|
||||
public void setEnableDragDrop(final boolean enableDragDrop) {
|
||||
this.enableDragDrop = enableDragDrop;
|
||||
}
|
||||
|
||||
public boolean isOffsetHourLabels() {
|
||||
return offsetHourLabels;
|
||||
}
|
||||
|
||||
public void setOffsetHourLabels(final boolean offsetHourLabels) {
|
||||
this.offsetHourLabels = offsetHourLabels;
|
||||
}
|
||||
|
||||
public Click getTimeBlockClickNumber() {
|
||||
return timeBlockClickNumber;
|
||||
}
|
||||
|
||||
public void setTimeBlockClickNumber(final Click timeBlockClickNumber) {
|
||||
this.timeBlockClickNumber = timeBlockClickNumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated As of release 0.9.4 removed since is not really needed
|
||||
*/
|
||||
@Deprecated
|
||||
public void setEnableDragDropCreation(final boolean dragDropCreation) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated As of release 0.9.4 removed since is not really needed
|
||||
*/
|
||||
@Deprecated
|
||||
public boolean getEnableDragDropCreation() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setDayStartsAt(int dayStartsAt) {
|
||||
this.dayStartsAt = dayStartsAt;
|
||||
DateUtils.setDayStartsAt(dayStartsAt);
|
||||
}
|
||||
|
||||
public int getDayStartsAt() {
|
||||
return dayStartsAt;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param showWeekNumbers
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public void setShowWeekNumbers(final boolean showWeekNumbers) {
|
||||
this.showWeekNumbers = showWeekNumbers;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public boolean isShowingWeekNumbers() {
|
||||
return showWeekNumbers;
|
||||
}
|
||||
|
||||
public void setHolidays(List<Date> holidays) {
|
||||
this.holidays = holidays;
|
||||
}
|
||||
|
||||
public List<Date> getHolidays() {
|
||||
return holidays;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public void setShowMultiday(final boolean visible) {
|
||||
this.showMultiDay = visible;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 0.9.4
|
||||
*/
|
||||
public boolean isMultidayVisible() {
|
||||
return showMultiDay;
|
||||
}
|
||||
|
||||
public enum Click {
|
||||
Double, Single, Drag
|
||||
}
|
||||
}
|
285
src/com/bradrydzewski/gwt/calendar/client/CalendarView.java
Normal file
285
src/com/bradrydzewski/gwt/calendar/client/CalendarView.java
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DaySelectionEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DaySelectionHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasDaySelectionHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasWeekSelectionHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.WeekSelectionEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.WeekSelectionHandler;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
|
||||
/**
|
||||
* Abstract base class defining the operations to render a calendar and
|
||||
* user-input dispatching methods. <p/> <p></p>Subclasses will provide the
|
||||
* details of rendering the calendar to visualize by day (Day View), monthly
|
||||
* (month view), agenda (list view) and the logic implementing the user-input
|
||||
* event processing.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public abstract class CalendarView implements HasSettings, HasWeekSelectionHandlers<Date>, HasDaySelectionHandlers<Date> {
|
||||
|
||||
/**
|
||||
* Calendar widget bound to the view.
|
||||
*
|
||||
* @see CalendarWidget
|
||||
*/
|
||||
protected CalendarWidget calendarWidget = null;
|
||||
|
||||
/**
|
||||
* Number of days the calendar should display at a given time, 3 by
|
||||
* default.
|
||||
*/
|
||||
private int displayedDays = 3;
|
||||
|
||||
/**
|
||||
* Attaches this view to the provided {@link CalendarWidget}.
|
||||
*
|
||||
* @param calendarWidget The interactive widget containing the calendar
|
||||
*/
|
||||
public void attach(CalendarWidget calendarWidget) {
|
||||
this.calendarWidget = calendarWidget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches this view from the currently associated {@link CalendarWidget}.
|
||||
* TODO: The CalendarWidget might still have a reference to this
|
||||
* CalendarView, is that correct??
|
||||
*/
|
||||
public void detatch() {
|
||||
calendarWidget = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the CSS style name of this calendar view.
|
||||
*
|
||||
* @return The CSS style that should be used when rendering this calendar
|
||||
* view
|
||||
*/
|
||||
public abstract String getStyleName();
|
||||
|
||||
public void doSizing() {
|
||||
}
|
||||
|
||||
public abstract void doLayout();
|
||||
|
||||
/**
|
||||
* Configures this view component's currently selected
|
||||
* <code>appointment</code>. Notification to the calendar widget associated
|
||||
* is optional and controlled with the <code>fireEvent</code> flag.
|
||||
*
|
||||
* @param appointment The appointment in the calendar in-memory model to be
|
||||
* configured as the currently selected
|
||||
* @param fireEvent Indicates whether a selection event should be
|
||||
* triggered by the parent widget so that it informs its
|
||||
* set of registered listeners about the change
|
||||
*/
|
||||
// public void setSelectedAppointment(Appointment appointment,
|
||||
// boolean fireEvent) {
|
||||
// calendarWidget.setSelectedAppointment(appointment);
|
||||
// if (fireEvent) {
|
||||
// calendarWidget.fireSelectionEvent(appointment);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* Configures this view component's currently selected
|
||||
* <code>appointment</code> and notifies widget about the change in the
|
||||
* model state.
|
||||
*
|
||||
* @param appointment The appointment in the calendar in-memory model to be
|
||||
* configured as the currently selected
|
||||
*/
|
||||
// public void setSelectedAppointment(Appointment appointment) {
|
||||
// setSelectedAppointment(appointment, true);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Returns the configured number of days the calendar should display at a
|
||||
* given time.
|
||||
*
|
||||
* @return The number of days this calendar view should display at a given
|
||||
* time
|
||||
*/
|
||||
public int getDisplayedDays() {
|
||||
return displayedDays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the configured number of days the calendar should display at a given
|
||||
* time.
|
||||
*
|
||||
* @param displayedDays The number of days this calendar view should display
|
||||
* at a given time
|
||||
*/
|
||||
public void setDisplayedDays(int displayedDays) {
|
||||
this.displayedDays = displayedDays;
|
||||
}
|
||||
|
||||
/* on clicks */
|
||||
public abstract void onDoubleClick(Element element, Event event);
|
||||
|
||||
public abstract void onSingleClick(Element element, Event event);
|
||||
|
||||
public abstract void onMouseOver(Element element, Event event);
|
||||
|
||||
/**
|
||||
* Processes user {@link com.google.gwt.event.dom.client.KeyCodes#KEY_DELETE}
|
||||
* and {@link com.google.gwt.event.dom.client.KeyCodes.KEY_BACKSPACE}
|
||||
* keystrokes. The <code>CalendarView</code> implementation is empty so that
|
||||
* subclasses are not forced to implement it if no specific logic is needed
|
||||
* for {@link com.google.gwt.event.dom.client.KeyCodes#KEY_DELETE} or
|
||||
* {@link com.google.gwt.event.dom.client.KeyCodes#KEY_BACKSPACE} keystrokes.
|
||||
*/
|
||||
public void onDeleteKeyPressed() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes user {@link com.google.gwt.event.dom.client.KeyCodes#KEY_UP}
|
||||
* keystrokes. The <code>CalendarView</code> implementation is empty so that
|
||||
* subclasses are not forced to implement it if no specific logic is needed
|
||||
* for {@link com.google.gwt.event.dom.client.KeyCodes#KEY_UP} keystrokes.
|
||||
*/
|
||||
public void onUpArrowKeyPressed() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes user {@link com.google.gwt.event.dom.client.KeyCodes#KEY_DOWN}
|
||||
* keystrokes. The <code>CalendarView</code> implementation is empty so that
|
||||
* subclasses are not forced to implement it if no specific logic is needed
|
||||
* for {@link com.google.gwt.event.dom.client.KeyCodes#KEY_DOWN}
|
||||
* keystrokes.
|
||||
*/
|
||||
public void onDownArrowKeyPressed() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes user {@link com.google.gwt.event.dom.client.KeyCodes#KEY_LEFT}
|
||||
* keystrokes. The <code>CalendarView</code> implementation is empty so that
|
||||
* subclasses are not forced to implement it if no specific logic is needed
|
||||
* for {@link com.google.gwt.event.dom.client.KeyCodes#KEY_LEFT}
|
||||
* keystrokes.
|
||||
*/
|
||||
public void onLeftArrowKeyPressed() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes user {@link com.google.gwt.event.dom.client.KeyCodes#KEY_RIGHT}
|
||||
* keystrokes. The <code>CalendarView</code> implementation is empty so that
|
||||
* subclasses are not forced to implement it if no specific logic is needed
|
||||
* for {@link com.google.gwt.event.dom.client.KeyCodes#KEY_RIGHT}
|
||||
* keystrokes.
|
||||
*/
|
||||
public void onRightArrowKeyPressed() {
|
||||
}
|
||||
|
||||
public abstract void onAppointmentSelected(Appointment appt);
|
||||
|
||||
public final void selectAppointment(Appointment appt) {
|
||||
calendarWidget.setSelectedAppointment(appt, true);
|
||||
}
|
||||
|
||||
public final void selectNextAppointment() {
|
||||
calendarWidget.selectNextAppointment();
|
||||
}
|
||||
|
||||
public final void selectPreviousAppointment() {
|
||||
calendarWidget.selectPreviousAppointment();
|
||||
}
|
||||
|
||||
public final void updateAppointment(Appointment toAppt) {
|
||||
calendarWidget.fireUpdateEvent(toAppt);
|
||||
}
|
||||
|
||||
public final void deleteAppointment(Appointment appt) {
|
||||
calendarWidget.fireDeleteEvent(appt);
|
||||
}
|
||||
|
||||
public final void openAppointment(Appointment appt) {
|
||||
calendarWidget.fireOpenEvent(appt);
|
||||
}
|
||||
|
||||
public final void createAppointment(Appointment appt) {
|
||||
createAppointment(appt.getStart(), appt.getEnd());
|
||||
}
|
||||
|
||||
public final void createAppointment(Date start, Date end) {
|
||||
calendarWidget.fireTimeBlockClickEvent(start);
|
||||
}
|
||||
|
||||
public void scrollToHour(int hour) {
|
||||
|
||||
}
|
||||
|
||||
public CalendarSettings getSettings() {
|
||||
return calendarWidget.getSettings();
|
||||
}
|
||||
|
||||
public void setSettings(CalendarSettings settings) {
|
||||
calendarWidget.setSettings(settings);
|
||||
}
|
||||
|
||||
protected void addDayClickHandler(final Label dayLabel, final Date day) {
|
||||
dayLabel.addClickHandler(new ClickHandler() {
|
||||
public void onClick(ClickEvent event) {
|
||||
fireSelectedDay(day);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void addWeekClickHandler(final Label weekLabel, final Date day) {
|
||||
weekLabel.addClickHandler(new ClickHandler() {
|
||||
public void onClick(ClickEvent event) {
|
||||
fireSelectedWeek(day);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void fireSelectedDay(final Date day) {
|
||||
DaySelectionEvent.fire(this, day);
|
||||
}
|
||||
|
||||
protected void fireSelectedWeek(final Date day) {
|
||||
WeekSelectionEvent.fire(this, day);
|
||||
}
|
||||
|
||||
public HandlerRegistration addWeekSelectionHandler(
|
||||
WeekSelectionHandler<Date> handler) {
|
||||
return calendarWidget.addHandler(handler, WeekSelectionEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addDaySelectionHandler(
|
||||
DaySelectionHandler<Date> handler) {
|
||||
return calendarWidget.addHandler(handler, DaySelectionEvent.getType());
|
||||
}
|
||||
|
||||
public void fireEvent(GwtEvent<?> event) {
|
||||
calendarWidget.fireEvent(event);
|
||||
}
|
||||
}
|
48
src/com/bradrydzewski/gwt/calendar/client/CalendarViews.java
Normal file
48
src/com/bradrydzewski/gwt/calendar/client/CalendarViews.java
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.agenda.AgendaView;
|
||||
import com.bradrydzewski.gwt.calendar.client.dayview.DayView;
|
||||
import com.bradrydzewski.gwt.calendar.client.monthview.MonthView;
|
||||
|
||||
/**
|
||||
* Enumeration that represents each standard {@link CalendarView}.
|
||||
* @author Brad Rydzewski
|
||||
* @since 0.9.0
|
||||
*/
|
||||
public enum CalendarViews {
|
||||
/**
|
||||
* Represents the {@link DayView}, which presents a set of
|
||||
* Appointments a single day at a time.
|
||||
*/
|
||||
DAY,
|
||||
/**
|
||||
* Represents the {@link MonthView}, which presents a set of
|
||||
* Appointments for a whole month.
|
||||
*/
|
||||
MONTH,
|
||||
/**
|
||||
* Represents the {@link AgendaView}, which presents a set of
|
||||
* Appointments as a list.
|
||||
*/
|
||||
AGENDA,
|
||||
|
||||
TECH,
|
||||
}
|
565
src/com/bradrydzewski/gwt/calendar/client/CalendarWidget.java
Normal file
565
src/com/bradrydzewski/gwt/calendar/client/CalendarWidget.java
Normal file
@ -0,0 +1,565 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.event.CreateEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.CreateHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DateRequestEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DateRequestHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DeleteEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DeleteHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasDateRequestHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasDeleteHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasMouseOverHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasTimeBlockClickHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasUpdateHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.MouseOverEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.MouseOverHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.TimeBlockClickEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.TimeBlockClickHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.UpdateEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.UpdateHandler;
|
||||
import com.google.gwt.core.client.Scheduler;
|
||||
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
|
||||
import com.google.gwt.event.logical.shared.HasOpenHandlers;
|
||||
import com.google.gwt.event.logical.shared.HasSelectionHandlers;
|
||||
import com.google.gwt.event.logical.shared.OpenEvent;
|
||||
import com.google.gwt.event.logical.shared.OpenHandler;
|
||||
import com.google.gwt.event.logical.shared.SelectionEvent;
|
||||
import com.google.gwt.event.logical.shared.SelectionHandler;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
/**
|
||||
* <code>CalendarWidget</code> is an {@link com.bradrydzewski.gwt.calendar.client.InteractiveWidget}
|
||||
* that maintains a calendar model (a set of {@link Appointment} objects)
|
||||
* managed through an {@link AppointmentManager}.
|
||||
* <p/>
|
||||
* TODO: Need Calendar "View" - CHECK
|
||||
* TODO: Need CalendarSettings
|
||||
* TODO: Need LayoutStrategy - CHECK
|
||||
* TODO: Need DragDropStrategy
|
||||
* TODO: Need ResizeStrategy ??? or is this same as DragDrop
|
||||
* TODO: Add AppointmentBuilder ??? downside is that if the Appointment object is updated, need to refersh widget
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @see com.bradrydzewski.gwt.calendar.client.InteractiveWidget
|
||||
*/
|
||||
public class CalendarWidget extends InteractiveWidget implements
|
||||
HasSelectionHandlers<Appointment>, HasDeleteHandlers<Appointment>,
|
||||
HasOpenHandlers<Appointment>, HasTimeBlockClickHandlers<Date>,
|
||||
HasUpdateHandlers<Appointment>, HasDateRequestHandlers<Date>,
|
||||
HasMouseOverHandlers<Appointment>,
|
||||
HasLayout, HasAppointments {
|
||||
|
||||
/**
|
||||
* Set to <code>true</code> if the calendar layout is suspended and cannot
|
||||
* be triggered.
|
||||
*/
|
||||
private boolean layoutSuspended = false;
|
||||
|
||||
/**
|
||||
* Set to <code>true</code> if the calendar is pending the layout of its
|
||||
* appointments.
|
||||
*/
|
||||
private boolean layoutPending = false;
|
||||
|
||||
/**
|
||||
* The date currently displayed by the calendar. Set to current system date
|
||||
* by default.
|
||||
*/
|
||||
private Date date;
|
||||
|
||||
/**
|
||||
* Calendar settings, set to default.
|
||||
*/
|
||||
private CalendarSettings settings = CalendarSettings.DEFAULT_SETTINGS;
|
||||
|
||||
/**
|
||||
* The component to manage the set of appointments displayed by this
|
||||
* <code>CalendarWidget</code>.
|
||||
*/
|
||||
private AppointmentManager appointmentManager = null;
|
||||
|
||||
private CalendarView view = null;
|
||||
|
||||
/**
|
||||
* Creates a <code>CalendarWidget</code> with an empty set of appointments
|
||||
* and the current system date as the date currently displayed by the
|
||||
* calendar.
|
||||
*/
|
||||
public CalendarWidget() {
|
||||
this(new Date());
|
||||
}
|
||||
|
||||
public CalendarWidget(Date date) {
|
||||
super();
|
||||
appointmentManager = new AppointmentManager();
|
||||
this.date = date;
|
||||
DateUtils.resetTime(this.date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the current view of this calendar widget to the specified
|
||||
* <code>view</code>. By setting this widget's current view the whole widget
|
||||
* panel is cleared.
|
||||
*
|
||||
* @param view The {@link CalendarView} implementation to render this
|
||||
* widget's underlying calendar
|
||||
*/
|
||||
public final void setView(CalendarView view) {
|
||||
this.getRootPanel().clear();
|
||||
this.view = view;
|
||||
this.view.attach(this);
|
||||
this.setStyleName(this.view.getStyleName());
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
public final CalendarView getView() {
|
||||
return view;
|
||||
}
|
||||
|
||||
public Date getDate() {
|
||||
return (Date) date.clone();
|
||||
}
|
||||
|
||||
public void setDate(Date date, int days) {
|
||||
Date dateCopy = (Date)date.clone();
|
||||
DateUtils.resetTime(dateCopy);
|
||||
this.date = dateCopy;
|
||||
view.setDisplayedDays(days);
|
||||
refresh();
|
||||
}
|
||||
|
||||
public void setDate(Date date) {
|
||||
setDate(date, getDays());
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves this calendar widget current <code>date</code> as many days as
|
||||
* specified by the <code>numOfDays</code> parameter.
|
||||
*
|
||||
* @param numOfDays The number of days to change the calendar date forward
|
||||
* (positive number) or backwards.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public void addDaysToDate(int numOfDays) {
|
||||
this.date.setDate(this.date.getDate() + numOfDays);
|
||||
}
|
||||
|
||||
public int getDays() {
|
||||
return view == null ? 3 : view.getDisplayedDays();
|
||||
}
|
||||
|
||||
public void setDays(int days) {
|
||||
view.setDisplayedDays(days);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the collection of appointments in the underlying in-memory model
|
||||
* of this calendar widget. <strong>Warning</strong>: the returned
|
||||
* collection of apointments can be modified by client code, possibly
|
||||
* breaking the system model invariants.
|
||||
*
|
||||
* @return The set of appointments to be displayed by this calendar widget
|
||||
* @see AppointmentManager#getAppointments()
|
||||
*/
|
||||
public List<Appointment> getAppointments() {
|
||||
return appointmentManager.getAppointments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an appointment from the calendar.
|
||||
*
|
||||
* @param appointment the item to be removed.
|
||||
*/
|
||||
public void removeAppointment(Appointment appointment) {
|
||||
removeAppointment(appointment, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the currently selected appointment from the model, if such
|
||||
* appointment is set.
|
||||
*/
|
||||
public void removeCurrentlySelectedAppointment() {
|
||||
appointmentManager.removeCurrentlySelectedAppointment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an appointment from the calendar.
|
||||
*
|
||||
* @param appointment the item to be removed.
|
||||
* @param fireEvents <code>true</code> to allow deletion events to be
|
||||
* fired
|
||||
*/
|
||||
public void removeAppointment(Appointment appointment, boolean fireEvents) {
|
||||
boolean commitChange = true;
|
||||
|
||||
if (fireEvents) {
|
||||
commitChange = DeleteEvent.fire(this, getSelectedAppointment());
|
||||
}
|
||||
|
||||
if (commitChange) {
|
||||
appointmentManager.removeAppointment(appointment);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the "currently selected" appointment of this calendar.
|
||||
*
|
||||
* @see com.bradrydzewski.gwt.calendar.client.AppointmentManager
|
||||
*/
|
||||
public void resetSelectedAppointment() {
|
||||
appointmentManager.resetSelectedAppointment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an appointment to the calendar.
|
||||
*
|
||||
* @param appointment item to be added
|
||||
*/
|
||||
public void addAppointment(Appointment appointment) {
|
||||
if (appointment == null) {
|
||||
throw new NullPointerException("Added appointment cannot be null.");
|
||||
}
|
||||
appointmentManager.addAppointment(appointment);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds each appointment in the list to the calendar.
|
||||
*
|
||||
* @param appointments items to be added.
|
||||
*/
|
||||
public void addAppointments(List<Appointment> appointments) {
|
||||
appointmentManager.addAppointments(appointments);
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears all appointment items.
|
||||
*/
|
||||
public void clearAppointments() {
|
||||
appointmentManager.clearAppointments();
|
||||
refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the currently selected item.
|
||||
*
|
||||
* @param appointment the item to be selected, or <code>null</code> to
|
||||
* de-select all items.
|
||||
*/
|
||||
public void setSelectedAppointment(Appointment appointment) {
|
||||
setSelectedAppointment(appointment, true);
|
||||
}
|
||||
|
||||
public void setSelectedAppointment(Appointment appointment,
|
||||
boolean fireEvents) {
|
||||
appointmentManager.setSelectedAppointment(appointment);
|
||||
if (fireEvents) {
|
||||
fireSelectionEvent(appointment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether there is a "currently selected" appointment
|
||||
* at the moment.
|
||||
*
|
||||
* @return <code>true</code> if there is an appointment currently selected,
|
||||
* <code>false</code> if it is <code>null</code>.
|
||||
* @see com.bradrydzewski.gwt.calendar.client.AppointmentManager#hasAppointmentSelected()
|
||||
*/
|
||||
public boolean hasAppointmentSelected() {
|
||||
return appointmentManager.hasAppointmentSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the currently selected item.
|
||||
*
|
||||
* @return the selected item.
|
||||
*/
|
||||
public Appointment getSelectedAppointment() {
|
||||
return appointmentManager.getSelectedAppointment();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether the passed <code>appointment</code> is the currently
|
||||
* selected appointment.
|
||||
*
|
||||
* @param appointment The appointment to test to be the currently selected
|
||||
* @return <code>true</code> if there is a currently selected appointment
|
||||
* and happens to be equal to the passed <code>appointment</code>
|
||||
* @see com.bradrydzewski.gwt.calendar.client.AppointmentManager#isTheSelectedAppointment(Appointment)
|
||||
*/
|
||||
public boolean isTheSelectedAppointment(Appointment appointment) {
|
||||
return appointmentManager.isTheSelectedAppointment(appointment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs all layout calculations for the list of appointments and resizes
|
||||
* the Calendar View appropriately.
|
||||
*/
|
||||
protected void refresh() {
|
||||
if (layoutSuspended) {
|
||||
layoutPending = true;
|
||||
return;
|
||||
}
|
||||
|
||||
appointmentManager.resetHoveredAppointment();
|
||||
appointmentManager.sortAppointments();
|
||||
|
||||
doLayout();
|
||||
doSizing();
|
||||
}
|
||||
|
||||
public void doLayout() {
|
||||
view.doLayout();
|
||||
}
|
||||
|
||||
public void doSizing() {
|
||||
view.doSizing();
|
||||
}
|
||||
|
||||
public void onLoad() {
|
||||
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
|
||||
public void execute() {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Suspends the calendar from performing a layout. This can be useful when
|
||||
* adding a large number of appointments at a time, since a layout is
|
||||
* performed each time an appointment is added.
|
||||
*/
|
||||
public void suspendLayout() {
|
||||
layoutSuspended = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the calendar to perform a layout, sizing the component and placing
|
||||
* all appointments. If a layout is pending it will get executed when this
|
||||
* method is called.
|
||||
*/
|
||||
public void resumeLayout() {
|
||||
layoutSuspended = false;
|
||||
|
||||
if (layoutPending) {
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public CalendarSettings getSettings() {
|
||||
return this.settings;
|
||||
}
|
||||
|
||||
public void setSettings(CalendarSettings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public void scrollToHour(int hour) {
|
||||
view.scrollToHour(hour);
|
||||
}
|
||||
|
||||
public boolean selectPreviousAppointment() {
|
||||
|
||||
boolean selected = appointmentManager.selectPreviousAppointment();
|
||||
if (selected) {
|
||||
fireSelectionEvent(getSelectedAppointment());
|
||||
}
|
||||
|
||||
return selected;
|
||||
}
|
||||
|
||||
public boolean selectNextAppointment() {
|
||||
boolean selected = appointmentManager.selectNextAppointment();
|
||||
if (selected) {
|
||||
fireSelectionEvent(getSelectedAppointment());
|
||||
}
|
||||
return selected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeleteKeyPressed() {
|
||||
view.onDeleteKeyPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDoubleClick(Element element, Event event) {
|
||||
view.onDoubleClick(element, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownArrowKeyPressed() {
|
||||
view.onDownArrowKeyPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLeftArrowKeyPressed() {
|
||||
view.onLeftArrowKeyPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMouseDown(Element element, Event event) {
|
||||
view.onSingleClick(element, event);
|
||||
}
|
||||
|
||||
public void onMouseOver(Element element, Event event) {
|
||||
view.onMouseOver(element, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRightArrowKeyPressed() {
|
||||
view.onRightArrowKeyPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpArrowKeyPressed() {
|
||||
view.onUpArrowKeyPressed();
|
||||
}
|
||||
|
||||
public void fireOpenEvent(Appointment appointment) {
|
||||
OpenEvent.fire(this, appointment);
|
||||
}
|
||||
|
||||
public void fireDeleteEvent(Appointment appointment) {
|
||||
|
||||
//fire the event to notify the client
|
||||
boolean allow = DeleteEvent.fire(this, appointment);
|
||||
|
||||
if (allow) {
|
||||
appointmentManager.removeAppointment(appointment);
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void fireSelectionEvent(Appointment appointment) {
|
||||
view.onAppointmentSelected(appointment);
|
||||
SelectionEvent.fire(this, appointment);
|
||||
}
|
||||
|
||||
public void fireMouseOverEvent(
|
||||
Appointment appointment, Element element) {
|
||||
//we need to make sure we aren't re-firing the event
|
||||
// for the same appointment. This is a bit problematic,
|
||||
// because the mouse over event will fire for an appointment's
|
||||
// child elements (title label, footer, body, for example)
|
||||
// and will cause this method to be called with a null
|
||||
// appointment. this is a temp workaround, but basically
|
||||
// an appointment cannot be hovered twice in a row
|
||||
if (appointment != null
|
||||
&& !appointment.equals(appointmentManager
|
||||
.getHoveredAppointment())) {
|
||||
appointmentManager.setHoveredAppointment(appointment);
|
||||
MouseOverEvent.fire(this, appointment, element);
|
||||
}
|
||||
}
|
||||
|
||||
public void fireTimeBlockClickEvent(Date date) {
|
||||
TimeBlockClickEvent.fire(this, date);
|
||||
}
|
||||
|
||||
public void fireCreateEvent(Appointment appointment) {
|
||||
boolean allow = CreateEvent.fire(this, appointment);
|
||||
if (!allow) {
|
||||
appointmentManager.rollback();
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public void fireDateRequestEvent(Date date) {
|
||||
DateRequestEvent.fire(this, date);
|
||||
}
|
||||
|
||||
public void fireDateRequestEvent(Date date, Element clicked) {
|
||||
DateRequestEvent.fire(this, date, clicked);
|
||||
}
|
||||
|
||||
public void fireUpdateEvent(Appointment appointment) {
|
||||
//refresh the appointment
|
||||
refresh();
|
||||
//fire the event to notify the client
|
||||
boolean allow = UpdateEvent.fire(this, appointment);
|
||||
|
||||
if (!allow) {
|
||||
appointmentManager.rollback();
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public HandlerRegistration addSelectionHandler(
|
||||
SelectionHandler<Appointment> handler) {
|
||||
return addHandler(handler, SelectionEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addDeleteHandler(
|
||||
DeleteHandler<Appointment> handler) {
|
||||
return addHandler(handler, DeleteEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseOverHandler(
|
||||
MouseOverHandler<Appointment> handler) {
|
||||
return addHandler(handler, MouseOverEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addTimeBlockClickHandler(
|
||||
TimeBlockClickHandler<Date> handler) {
|
||||
return addHandler(handler, TimeBlockClickEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addUpdateHandler(UpdateHandler<Appointment> handler) {
|
||||
return addHandler(handler, UpdateEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addCreateHandler(
|
||||
CreateHandler<Appointment> handler) {
|
||||
return addHandler(handler, CreateEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addOpenHandler(
|
||||
OpenHandler<Appointment> handler) {
|
||||
return addHandler(handler, OpenEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addDateRequestHandler(
|
||||
DateRequestHandler<Date> handler) {
|
||||
return addHandler(handler, DateRequestEvent.getType());
|
||||
}
|
||||
|
||||
public void addToRootPanel(Widget widget) {
|
||||
getRootPanel().add(widget);
|
||||
}
|
||||
|
||||
public void setRollbackAppointment(Appointment appt) {
|
||||
appointmentManager.setRollbackAppointment(appt);
|
||||
}
|
||||
|
||||
public void setCommittedAppointment(Appointment appt) {
|
||||
appointmentManager.setCommittedAppointment(appt);
|
||||
}
|
||||
}
|
405
src/com/bradrydzewski/gwt/calendar/client/DateUtils.java
Normal file
405
src/com/bradrydzewski/gwt/calendar/client/DateUtils.java
Normal file
@ -0,0 +1,405 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009-2011 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Contains utility methods involving dates. This class should remain GWT-API
|
||||
* independent.
|
||||
*
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class DateUtils {
|
||||
|
||||
/**
|
||||
* Number of milliseconds in a day.
|
||||
*/
|
||||
public static final long MILLIS_IN_A_DAY = 1000 * 60 * 60 * 24;
|
||||
/**
|
||||
* Defines the Number of Days in a Week.
|
||||
*/
|
||||
public static final int DAYS_IN_A_WEEK = 7;
|
||||
|
||||
private static int dayStartsAt = 0;
|
||||
|
||||
public static void setDayStartsAt(int start) {
|
||||
dayStartsAt = start;
|
||||
}
|
||||
|
||||
public static int getDayStartsAt() {
|
||||
return dayStartsAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a <code>null</code>-safe way to return the number of milliseconds
|
||||
* on a <code>date</code>.
|
||||
*
|
||||
* @param date The date whose value in milliseconds will be returned
|
||||
* @return The number of milliseconds in <code>date</code>, <code>0</code>
|
||||
* (zero) if <code>date</code> is <code>null</code>.
|
||||
*/
|
||||
private static long safeInMillis(Date date) {
|
||||
return date != null ? date.getTime() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of days between the passed dates.
|
||||
*
|
||||
* @param endDate The upper limit of the date range
|
||||
* @param startDate The lower limit of the date range
|
||||
* @return The number of days between <code>endDate</code> and
|
||||
* <code>starDate</code> (inclusive)
|
||||
*/
|
||||
@SuppressWarnings(value = "deprecation")
|
||||
public static int differenceInDays(Date endDate, Date startDate) {
|
||||
int difference = 0;
|
||||
if (!areOnTheSameDay(endDate, startDate)) {
|
||||
int endDateOffset = -(endDate.getTimezoneOffset() * 60 * 1000);
|
||||
long endDateInstant = endDate.getTime() + endDateOffset;
|
||||
int startDateOffset = -(startDate.getTimezoneOffset() * 60 * 1000);
|
||||
long startDateInstant = startDate.getTime() + startDateOffset;
|
||||
double differenceDouble =
|
||||
(double) Math.abs(endDateInstant - startDateInstant) /
|
||||
(double) MILLIS_IN_A_DAY;
|
||||
differenceDouble = Math.max(1.0D, differenceDouble);
|
||||
difference = (int) differenceDouble;
|
||||
}
|
||||
return difference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full year (4-digits) of the passed <code>date</code>.
|
||||
* @param date The date whose year will be returned
|
||||
* @return The full year of the passed <code>date</code>.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static int year(Date date) {
|
||||
return 1900 + date.getYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves a date <code>shift</code> days. A clone of <code>date</code> to
|
||||
* prevent undesired object modifications.
|
||||
*
|
||||
* @param date The date to shift
|
||||
* @param shift The number of days to push the original <code>date</code>
|
||||
* <em>forward</em>
|
||||
* @return A <em>new</em> date pushed <code>shift</code> days forward
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Date shiftDate(Date date, int shift) {
|
||||
Date result = (Date) date.clone();
|
||||
result.setDate(date.getDate() + shift);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the date to have no time modifiers (hours, minutes, seconds.)
|
||||
*
|
||||
* @param date The date to reset
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void resetTime(Date date) {
|
||||
long milliseconds = safeInMillis(date);
|
||||
milliseconds = (milliseconds / 1000) * 1000;
|
||||
date.setTime(milliseconds);
|
||||
date.setHours(DateUtils.getDayStartsAt());
|
||||
date.setMinutes(0);
|
||||
date.setSeconds(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether two dates are on the same date by comparing their day,
|
||||
* month and year values. Time values such as hours and minutes are not
|
||||
* considered in this comparison.
|
||||
*
|
||||
* @param dateOne The first date to test
|
||||
* @param dateTwo The second date to test
|
||||
* @return <code>true</code> if both dates have their <code>date</code>,
|
||||
* <code>month</code> and <code>year</code> properties with the
|
||||
* <em>exact</em> same values (whatever they are)
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean areOnTheSameDay(Date dateOne, Date dateTwo) {
|
||||
Date end;
|
||||
Date start;
|
||||
|
||||
if (dateTwo.getTime() > dateOne.getTime()) {
|
||||
end = (Date) dateTwo.clone();
|
||||
start = (Date) dateOne.clone();
|
||||
} else {
|
||||
start = (Date) dateTwo.clone();
|
||||
end = (Date) dateOne.clone();
|
||||
}
|
||||
|
||||
if (DateUtils.dayStartsAt != 0) {
|
||||
long time = start.getTime()
|
||||
- (1000 * 60 * 60 * DateUtils.dayStartsAt);
|
||||
start = new Date(time);
|
||||
|
||||
time = end.getTime()
|
||||
- (1000 * 60 * 60 * DateUtils.dayStartsAt);
|
||||
end = new Date(time);
|
||||
}
|
||||
|
||||
return start.getDate() == end.getDate()
|
||||
&& start.getMonth() == end.getMonth()
|
||||
&& start.getYear() == end.getYear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether two dates are on the same month of the same year.
|
||||
*
|
||||
* @param dateOne The first date of the comparison
|
||||
* @param dateTwo The second date of the comparison
|
||||
* @return <code>true</code> if both dates have the same year and month,
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean areOnTheSameMonth(Date dateOne, Date dateTwo) {
|
||||
Date end = (Date)dateTwo.clone();
|
||||
|
||||
if (DateUtils.dayStartsAt != 0) {
|
||||
long time = end.getTime() - (1000 * 60 * 60 * DateUtils.dayStartsAt);
|
||||
end = new Date(time);
|
||||
}
|
||||
|
||||
return dateOne.getYear() == end.getYear() &&
|
||||
dateOne.getMonth() == end.getMonth();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a clone of the <code>anyDayInMonth</code> date set to the
|
||||
* <em>first</em> day of whatever its month is.
|
||||
*
|
||||
* @param anyDayInMonth Any date on a month+year
|
||||
* @return A clone of the <code>anyDayInMonth</code> date, representing the
|
||||
* first day of that same month and year
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Date firstOfTheMonth(Date anyDayInMonth) {
|
||||
Date first = (Date) anyDayInMonth.clone();
|
||||
first.setDate(1);
|
||||
return first;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the date of the passed object to be one day after whatever date it
|
||||
* has.
|
||||
*
|
||||
* @param date An object representing a date
|
||||
* @return The day
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Date moveOneDayForward(Date date) {
|
||||
date.setDate(date.getDate() + 1);
|
||||
return date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date corresponding to the first day of the next month relative
|
||||
* to the passed <code>date</code>.
|
||||
*
|
||||
* @param date The reference date
|
||||
* @return The first day of the next month, if the month of the passed date
|
||||
* corresponds to december (<code>11</code>) <em>one</em> will be
|
||||
* added to the year of the returned date.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Date firstOfNextMonth(Date date) {
|
||||
Date firstOfNextMonth = null;
|
||||
if (date != null) {
|
||||
int year = date.getMonth() == 11 ? date.getYear() + 1 : date.getYear();
|
||||
firstOfNextMonth = new Date(year, date.getMonth() + 1 % 11, 1);
|
||||
}
|
||||
return firstOfNextMonth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a day <em>exactly</em> 24 hours before the instant passed as
|
||||
* <code>date</code>. // TODO: This logic should address the time zone
|
||||
* offset
|
||||
*
|
||||
* @param date A point in time from which the moment 24 hours before will be
|
||||
* calculated
|
||||
* @return A new object <em>24</em> hours prior to the passed
|
||||
* <code>date</code>
|
||||
*/
|
||||
public static Date previousDay(Date date) {
|
||||
return new Date(date.getTime() - MILLIS_IN_A_DAY);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copies the hours, minutes and seconds in the <code>source</code> date into
|
||||
* the <code>target</code> date object.
|
||||
*
|
||||
* @param source The date with the hour, minutes and seconds to be copied
|
||||
* @param target The date whose time fields will be set
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static void copyTime(Date source, Date target) {
|
||||
target.setHours(source.getHours());
|
||||
target.setMinutes(source.getMinutes());
|
||||
target.setSeconds(source.getSeconds());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of minutes elapsed since the beginning of the passed
|
||||
* <code>day</code>.
|
||||
*
|
||||
* @param day The day to calculate the elapsed minutes
|
||||
* @return The number of minutes since <code>day</code> started
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static int minutesSinceDayStarted(Date day) {
|
||||
int minutes = (day.getHours() - dayStartsAt) * 60 + day.getMinutes();
|
||||
if (day.getHours() < dayStartsAt) {
|
||||
minutes = ((24 - dayStartsAt) + day.getHours()) * 60 + day.getMinutes();
|
||||
}
|
||||
return minutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new date with whatever date/time the passed <code>date</code>
|
||||
* object represents.
|
||||
*
|
||||
* @param date The source date
|
||||
* @return A new date object representing the same date and time as the passed
|
||||
* object
|
||||
*/
|
||||
public static Date newDate(Date date) {
|
||||
Date result = null;
|
||||
if (date != null) {
|
||||
result = new Date(date.getTime());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean isWeekend(final Date day) {
|
||||
return day.getDay()==0 || day.getDay()==6;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Integer weekday(final Date date) {
|
||||
int firstDayOfWeek = Integer.valueOf(CalendarFormat.INSTANCE.getFirstDayOfWeek());
|
||||
|
||||
int weekday = date.getDay();
|
||||
if ((firstDayOfWeek == 1) && (weekday == 0)) {
|
||||
weekday = 7;
|
||||
}
|
||||
return weekday;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static int calendarWeekIso(final Date inputDate) {
|
||||
final int daysWeek = 7;
|
||||
int firstDayOfWeek = Integer.valueOf(CalendarFormat.INSTANCE.getFirstDayOfWeek());
|
||||
|
||||
int thursdayDay = 4 + firstDayOfWeek;
|
||||
|
||||
Date thisThursday = new Date(inputDate.getYear(), inputDate.getMonth(),
|
||||
inputDate.getDate() - weekday(inputDate) + thursdayDay);
|
||||
|
||||
Date firstThursdayOfYear = new Date(thisThursday.getYear(), 0, 1);
|
||||
|
||||
while (weekday(firstThursdayOfYear) != thursdayDay) {
|
||||
firstThursdayOfYear.setDate(firstThursdayOfYear.getDate() + 1);
|
||||
}
|
||||
|
||||
Date firstMondayOfYear = new Date(firstThursdayOfYear.getYear(), 0,
|
||||
firstThursdayOfYear.getDate() - 3);
|
||||
|
||||
Long cw = (thisThursday.getTime() - firstMondayOfYear.getTime())
|
||||
/ MILLIS_IN_A_DAY / daysWeek + 1;
|
||||
|
||||
return cw.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or subtracts the specified amount of days for the given Date.
|
||||
*
|
||||
* @param date
|
||||
* A point in time
|
||||
* @param days
|
||||
* Number of days to add or substract
|
||||
* @return A new object <em>days</em> after to the passed <code>date</code>
|
||||
*/
|
||||
public static Date addDays(final Date date, final int days) {
|
||||
return new Date(date.getTime() + (days * MILLIS_IN_A_DAY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or subtracts the specified amount of weeks for the given Date.
|
||||
*
|
||||
* @param date
|
||||
* A point in time
|
||||
* @param weeks
|
||||
* Number of weeks to add or substract
|
||||
* @return A new object <em>weeks</em> after to the passed <code>date</code>
|
||||
*/
|
||||
public static Date addWeeks(final Date date, final int weeks) {
|
||||
return new Date(date.getTime() + (weeks * (MILLIS_IN_A_DAY * DAYS_IN_A_WEEK)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or subtracts the specified amount of months for the given Date.
|
||||
*
|
||||
* @param date
|
||||
* A point in time
|
||||
* @param months
|
||||
* Number of months to add or substract
|
||||
* @return A new object <em>weeks</em> after to the passed <code>date</code>
|
||||
*/
|
||||
public static Date addMonths(final Date date, final int months) {
|
||||
return new Date(date.getTime() + (months * (MILLIS_IN_A_DAY * DAYS_IN_A_WEEK)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of days between <code>start</code> and
|
||||
* <code>end</code>. The calculation is rounded to take in account
|
||||
* the saving day calculation.
|
||||
*
|
||||
* @param start
|
||||
* The first day in the period
|
||||
* @param end
|
||||
* The last day in the period
|
||||
* @return The number of days between <code>start</code> and
|
||||
* <code>end</code>, the minimum difference being one (
|
||||
* <code>1</code>)
|
||||
*/
|
||||
public static int daysInPeriod(final Date start, final Date end) {
|
||||
long diff = end.getTime() - start.getTime();
|
||||
double days = ((double)diff / MILLIS_IN_A_DAY) + 1;
|
||||
|
||||
Long result = Math.round(days);
|
||||
return result.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the amount of days in the month the
|
||||
* @param day
|
||||
* @return
|
||||
*/
|
||||
public static int daysInMonth(final Date date) {
|
||||
return 32 - new Date(date.getYear(), date.getMonth(), 32).getDate();
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface HasAppointments {
|
||||
|
||||
void removeAppointment(Appointment appointment);
|
||||
void removeAppointment(Appointment appointment, boolean fireEvents);
|
||||
void addAppointment(Appointment appointment);
|
||||
void addAppointments(List<Appointment> appointments);
|
||||
void clearAppointments();
|
||||
Appointment getSelectedAppointment();
|
||||
void setSelectedAppointment(Appointment appointment);
|
||||
void setSelectedAppointment(Appointment appointment,
|
||||
boolean fireEvents);
|
||||
boolean hasAppointmentSelected();
|
||||
}
|
21
src/com/bradrydzewski/gwt/calendar/client/HasLayout.java
Normal file
21
src/com/bradrydzewski/gwt/calendar/client/HasLayout.java
Normal file
@ -0,0 +1,21 @@
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
public interface HasLayout {
|
||||
|
||||
/**
|
||||
* Forces the widget to re-calculate and perform
|
||||
* layout operations.
|
||||
*/
|
||||
public void doLayout();
|
||||
|
||||
/**
|
||||
* Suspends the widget from performing layout operations.
|
||||
*/
|
||||
public void suspendLayout();
|
||||
|
||||
/**
|
||||
* Enables the widget to perform layout operations. Any pending layout
|
||||
* operations will be executed.
|
||||
*/
|
||||
public void resumeLayout();
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
public interface HasSettings {
|
||||
|
||||
public CalendarSettings getSettings();
|
||||
public void setSettings(CalendarSettings settings);
|
||||
}
|
253
src/com/bradrydzewski/gwt/calendar/client/InteractiveWidget.java
Normal file
253
src/com/bradrydzewski/gwt/calendar/client/InteractiveWidget.java
Normal file
@ -0,0 +1,253 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
import com.google.gwt.event.dom.client.KeyCodes;
|
||||
import com.google.gwt.event.dom.client.KeyDownEvent;
|
||||
import com.google.gwt.event.dom.client.KeyDownHandler;
|
||||
import com.google.gwt.event.dom.client.KeyPressEvent;
|
||||
import com.google.gwt.event.dom.client.KeyPressHandler;
|
||||
import com.google.gwt.event.dom.client.KeyUpEvent;
|
||||
import com.google.gwt.event.dom.client.KeyUpHandler;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.ui.ComplexPanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.FocusPanel;
|
||||
import com.google.gwt.user.client.ui.RootPanel;
|
||||
|
||||
/**
|
||||
* Abstract class for widgets that react to keystrokes and mouse gestures
|
||||
* providing a centralized place for the association between user inputs and the
|
||||
* logic to perform. Subclasses will implement the <code>onXXXKeyPressed</code>,
|
||||
* <code>onMouseDown</code> and <code>onDoubleClick</code> methods to provide
|
||||
* the custom event processing logic.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public abstract class InteractiveWidget extends Composite {
|
||||
|
||||
/**
|
||||
* Focus widget used to add keyboard and mouse focus to a calendar.
|
||||
*/
|
||||
private FocusPanel focusPanel = new FocusPanel();
|
||||
|
||||
/**
|
||||
* Main panel hold all other components.
|
||||
*/
|
||||
protected FlowPanel rootPanel = new FlowPanel();
|
||||
|
||||
/**
|
||||
* Used by focus widget to make sure a key stroke is only handled once by
|
||||
* the calendar.
|
||||
*/
|
||||
private boolean lastWasKeyDown = false;
|
||||
|
||||
public InteractiveWidget() {
|
||||
|
||||
initWidget(rootPanel);
|
||||
|
||||
//Sink events, mouse and keyboard for now
|
||||
sinkEvents(Event.ONMOUSEDOWN | Event.ONDBLCLICK | Event.KEYEVENTS | Event.ONMOUSEOVER);
|
||||
|
||||
hideFocusPanel();
|
||||
|
||||
//Add key handler events to the focus panel
|
||||
focusPanel.addKeyPressHandler(new KeyPressHandler() {
|
||||
public void onKeyPress(KeyPressEvent event) {
|
||||
if (!lastWasKeyDown) {
|
||||
keyboardNavigation(event.getNativeEvent().getKeyCode());
|
||||
}
|
||||
lastWasKeyDown = false;
|
||||
}
|
||||
});
|
||||
|
||||
focusPanel.addKeyUpHandler(new KeyUpHandler() {
|
||||
public void onKeyUp(KeyUpEvent event) {
|
||||
lastWasKeyDown = false;
|
||||
}
|
||||
});
|
||||
focusPanel.addKeyDownHandler(new KeyDownHandler() {
|
||||
public void onKeyDown(KeyDownEvent event) {
|
||||
keyboardNavigation(event.getNativeEvent().getKeyCode());
|
||||
lastWasKeyDown = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the widget's focus panel invisible.
|
||||
*/
|
||||
private void hideFocusPanel() {
|
||||
/*
|
||||
focusPanel.setVisible(false);
|
||||
RootPanel.get().add(focusPanel);
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "position", "absolute");
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "top", "0");
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "left", "0");
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "height", "100%");
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "width", "100%");
|
||||
*/
|
||||
RootPanel.get().add(focusPanel);
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "position", "absolute");
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "top", "-10");
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "left", "-10");
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "height", "0px");
|
||||
DOM.setStyleAttribute(focusPanel.getElement(), "width", "0px");
|
||||
}
|
||||
|
||||
public ComplexPanel getRootPanel() {
|
||||
return rootPanel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes mouse double-click events. Concrete interactive widgets should
|
||||
* provide the component's specific logic.
|
||||
*
|
||||
* @param element The HTML DOM element that originated the event
|
||||
*/
|
||||
public abstract void onDoubleClick(Element element, Event event);
|
||||
|
||||
/**
|
||||
* Processes mouse over events. Concrete interactive widgets
|
||||
* should provide the component's specific logic.
|
||||
*
|
||||
* @param element The HTML DOM element that originated the event
|
||||
* @param event The HTML DOM event that was triggered
|
||||
*/
|
||||
public abstract void onMouseOver(Element element, Event event);
|
||||
|
||||
/**
|
||||
* Processes mouse button pressing events. Concrete interactive widgets
|
||||
* should provide the component's specific logic.
|
||||
*
|
||||
* @param element The HTML DOM element that originated the event
|
||||
*/
|
||||
public abstract void onMouseDown(Element element, Event event);
|
||||
|
||||
/**
|
||||
* Processes {@link com.google.gwt.event.dom.client.KeyCodes.KEY_DELETE}
|
||||
* and {@link com.google.gwt.event.dom.client.KeyCodes.KEY_BACKSPACE}
|
||||
* keystrokes. Concrete interactive widgets should provide the component's
|
||||
* specific logic.
|
||||
*/
|
||||
public abstract void onDeleteKeyPressed();
|
||||
|
||||
/**
|
||||
* Processes {@link com.google.gwt.event.dom.client.KeyCodes.KEY_UP}
|
||||
* keystrokes. Concrete interactive widgets should provide the component's
|
||||
* specific logic.
|
||||
*/
|
||||
public abstract void onUpArrowKeyPressed();
|
||||
|
||||
/**
|
||||
* Processes {@link com.google.gwt.event.dom.client.KeyCodes.KEY_DOWN}
|
||||
* keystrokes. Concrete interactive widgets should provide the component's
|
||||
* specific logic.
|
||||
*/
|
||||
public abstract void onDownArrowKeyPressed();
|
||||
|
||||
/**
|
||||
* Processes {@link com.google.gwt.event.dom.client.KeyCodes.KEY_LEFT}
|
||||
* keystrokes. Concrete interactive widgets should provide the component's
|
||||
* specific logic.
|
||||
*/
|
||||
public abstract void onLeftArrowKeyPressed();
|
||||
|
||||
/**
|
||||
* Processes {@link com.google.gwt.event.dom.client.KeyCodes.KEY_RIGHT}
|
||||
* keystrokes. Concrete interactive widgets should provide the component's
|
||||
* specific logic.
|
||||
*/
|
||||
public abstract void onRightArrowKeyPressed();
|
||||
|
||||
@Override
|
||||
public void onBrowserEvent(Event event) {
|
||||
int eventType = DOM.eventGetType(event);
|
||||
Element element = DOM.eventGetTarget(event);
|
||||
|
||||
switch (eventType) {
|
||||
case Event.ONDBLCLICK: {
|
||||
onDoubleClick(element, event);
|
||||
focusPanel.setFocus(true);
|
||||
break;
|
||||
}
|
||||
case Event.ONMOUSEDOWN: {
|
||||
if (DOM.eventGetCurrentTarget(event) == getElement()) {
|
||||
|
||||
onMouseDown(element, event);
|
||||
focusPanel.setFocus(true);
|
||||
//Cancel events so Firefox / Chrome don't
|
||||
//give child widgets with scrollbars focus.
|
||||
//TODO: Should not cancel onMouseDown events in the event an appointment would have a child widget with a scrollbar (if this would ever even happen).
|
||||
DOM.eventCancelBubble(event, true);
|
||||
DOM.eventPreventDefault(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
case Event.ONMOUSEOVER:{
|
||||
if (DOM.eventGetCurrentTarget(event) == getElement()){
|
||||
onMouseOver(element, event);
|
||||
DOM.eventCancelBubble(event, true);
|
||||
DOM.eventPreventDefault(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.onBrowserEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches the processing of a key being pressed to the this widget
|
||||
* <code>onXXXXKeyPressed</code> methods.
|
||||
*
|
||||
* @param key Pressed key code
|
||||
*/
|
||||
protected void keyboardNavigation(int key) {
|
||||
switch (key) {
|
||||
case KeyCodes.KEY_BACKSPACE: {
|
||||
onDeleteKeyPressed();
|
||||
break;
|
||||
}
|
||||
case KeyCodes.KEY_DELETE: {
|
||||
onDeleteKeyPressed();
|
||||
break;
|
||||
}
|
||||
case KeyCodes.KEY_LEFT: {
|
||||
onLeftArrowKeyPressed();
|
||||
break;
|
||||
}
|
||||
case KeyCodes.KEY_UP: {
|
||||
onUpArrowKeyPressed();
|
||||
break;
|
||||
}
|
||||
case KeyCodes.KEY_RIGHT: {
|
||||
onRightArrowKeyPressed();
|
||||
break;
|
||||
}
|
||||
case KeyCodes.KEY_DOWN: {
|
||||
onDownArrowKeyPressed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2011 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client;
|
||||
|
||||
/**
|
||||
* Defines the style attribute values that will vary with a theme
|
||||
* when a particular theme+style is applied. The currently active
|
||||
* {@link com.bradrydzewski.gwt.calendar.client.monthview.MonthViewStyleManager} or
|
||||
* {@link com.bradrydzewski.gwt.calendar.client.dayview.DayViewStyleManager} will use the
|
||||
* strings in the theme style to style the elements in the view.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @author Carlos D. Morales
|
||||
*
|
||||
* @see com.bradrydzewski.gwt.calendar.theme.google.client.GoogleAppointmentStyle
|
||||
* @see com.bradrydzewski.gwt.calendar.theme.ical.client.ICalAppointmentStyle
|
||||
*/
|
||||
public interface ThemeAppointmentStyle {
|
||||
|
||||
public String getBackgroundHeader();
|
||||
|
||||
public String getBackground();
|
||||
|
||||
public String getSelectedBorder();
|
||||
|
||||
public String getHeaderText();
|
||||
|
||||
public String getSelectedBackgroundImage();
|
||||
|
||||
public String getBorder();
|
||||
}
|
397
src/com/bradrydzewski/gwt/calendar/client/agenda/AgendaView.java
Normal file
397
src/com/bradrydzewski/gwt/calendar/client/agenda/AgendaView.java
Normal file
@ -0,0 +1,397 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client.agenda;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.Attendee;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarView;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarWidget;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.AppointmentUtil;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
import com.google.gwt.user.client.ui.InlineLabel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public class AgendaView extends CalendarView {
|
||||
|
||||
/**
|
||||
* Adapter class that maps an Appointment to the widgets (DIV's, etc) that represent
|
||||
* it on the screen. This is necessary because a single appointment is represented by
|
||||
* many widgets. For example, an appointment is represented by a title widget,
|
||||
* a description widget, and has a "get more details" label.
|
||||
*
|
||||
* By mapping an appointment to these widgets we can easily figure out which
|
||||
* appointment the user is interacting with as they click around the AgendaView.
|
||||
* @author Brad Rydzewski
|
||||
* @version 1.0
|
||||
* @since 0.9.0
|
||||
*/
|
||||
class AgendaViewAppointmentAdapter {
|
||||
private Widget titleLabel;
|
||||
private Widget dateLabel;
|
||||
private Widget detailsLabel;
|
||||
private Appointment appointment;
|
||||
private Widget detailsPanel;
|
||||
|
||||
public AgendaViewAppointmentAdapter(Widget titleLabel, Widget dateLabel,
|
||||
Widget detailsPanel, Widget detailsLabel, Appointment appointment) {
|
||||
super();
|
||||
this.titleLabel = titleLabel;
|
||||
this.dateLabel = dateLabel;
|
||||
this.detailsLabel = detailsLabel;
|
||||
this.detailsPanel = detailsPanel;
|
||||
this.appointment = appointment;
|
||||
}
|
||||
|
||||
public Widget getTitleLabel() {
|
||||
return titleLabel;
|
||||
}
|
||||
|
||||
public Widget getDateLabel() {
|
||||
return dateLabel;
|
||||
}
|
||||
|
||||
public Widget getDetailsLabel() {
|
||||
return detailsLabel;
|
||||
}
|
||||
|
||||
public Appointment getAppointment() {
|
||||
return appointment;
|
||||
}
|
||||
|
||||
public Widget getDetailsPanel() {
|
||||
return detailsPanel;
|
||||
}
|
||||
}
|
||||
|
||||
class AppointmentDetailPanel extends Composite {
|
||||
|
||||
private Label moreDetailsRow = new Label();
|
||||
|
||||
public AppointmentDetailPanel(SimplePanel detailContainer, Appointment appt) {
|
||||
initWidget(detailContainer);
|
||||
|
||||
// add the detail widget
|
||||
detailContainer.setStyleName("detailContainer");
|
||||
AbsolutePanel detailDecorator = new AbsolutePanel();
|
||||
detailDecorator.setStyleName("detailDecorator");
|
||||
detailContainer.setVisible(false);
|
||||
detailContainer.add(detailDecorator);
|
||||
|
||||
if (appt.getLocation() != null
|
||||
&& !appt.getLocation().isEmpty()) {
|
||||
AbsolutePanel whereRow = new AbsolutePanel();
|
||||
InlineLabel whereHeader = new InlineLabel("Where: ");
|
||||
whereHeader.setStyleName("detailHeader");
|
||||
whereRow.add(whereHeader);
|
||||
whereRow.add(new InlineLabel(appt.getLocation()));
|
||||
detailDecorator.add(whereRow);
|
||||
}
|
||||
if (appt.getCreatedBy() != null
|
||||
&& !appt.getCreatedBy().isEmpty()) {
|
||||
AbsolutePanel creatorRow = new AbsolutePanel();
|
||||
InlineLabel creatorHeader = new InlineLabel("Creator: ");
|
||||
creatorHeader.setStyleName("detailHeader");
|
||||
creatorRow.add(creatorHeader);
|
||||
creatorRow.add(new InlineLabel(appt.getCreatedBy()));
|
||||
detailDecorator.add(creatorRow);
|
||||
}
|
||||
if (appt.getAttendees() != null
|
||||
&& !appt.getAttendees().isEmpty()) {
|
||||
AbsolutePanel whoRow = new AbsolutePanel();
|
||||
InlineLabel whoHeader = new InlineLabel("Who: ");
|
||||
whoHeader.setStyleName("detailHeader");
|
||||
whoRow.add(whoHeader);
|
||||
for (int a = 0; a < appt.getAttendees().size(); a++) {
|
||||
Attendee attendee = appt.getAttendees().get(a);
|
||||
String comma = (a < appt.getAttendees().size() - 1) ? ", "
|
||||
: "";
|
||||
String labelText = attendee.getEmail() + comma;
|
||||
whoRow.add(new InlineLabel(labelText));
|
||||
}
|
||||
detailDecorator.add(whoRow);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
DOM.setInnerHTML(moreDetailsRow.getElement(),
|
||||
"more details»");
|
||||
|
||||
moreDetailsRow.setStyleName("moreDetailsButton");
|
||||
//moreDetailsRow.addClickHandler(appointmentClickHandler);
|
||||
detailDecorator.add(moreDetailsRow);
|
||||
}
|
||||
public Label getMoreDetailsLabel() {
|
||||
return moreDetailsRow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FlexTable used to display a list of appointments.
|
||||
*/
|
||||
private FlexTable appointmentGrid = new FlexTable();
|
||||
|
||||
/**
|
||||
* List of appointment adapters, used to map widgets to the appointments
|
||||
* they represent.
|
||||
*/
|
||||
private ArrayList<AgendaViewAppointmentAdapter> appointmentAdapterList =
|
||||
new ArrayList<AgendaViewAppointmentAdapter>();
|
||||
|
||||
/**
|
||||
* DateTime format used to represent a day.
|
||||
*/
|
||||
private static final DateTimeFormat DEFAULT_DATE_FORMAT =
|
||||
DateTimeFormat.getFormat("EEE MMM d");
|
||||
|
||||
/**
|
||||
* DateTime format used when displaying an appointments start and end time.
|
||||
*/
|
||||
private static final DateTimeFormat DEFAULT_TIME_FORMAT =
|
||||
DateTimeFormat.getShortTimeFormat();
|
||||
|
||||
/**
|
||||
* Style used to format this view.
|
||||
*/
|
||||
private String styleName = "gwt-cal-ListView";
|
||||
|
||||
/**
|
||||
* Adds the calendar view to the calendar widget and performs required formatting.
|
||||
*/
|
||||
public void attach(CalendarWidget widget) {
|
||||
super.attach(widget);
|
||||
|
||||
appointmentGrid.setCellPadding(5);
|
||||
appointmentGrid.setCellSpacing(0);
|
||||
appointmentGrid.setBorderWidth(0);
|
||||
appointmentGrid.setWidth("100%");
|
||||
//DOM.setStyleAttribute(appointmentGrid.getElement(), "tableLayout", "fixed");
|
||||
calendarWidget.getRootPanel().add(appointmentGrid);
|
||||
calendarWidget.getRootPanel().add(appointmentGrid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the style name associated with this particular view
|
||||
* @return Style name.
|
||||
*/
|
||||
public String getStyleName() {
|
||||
return styleName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doLayout() {
|
||||
|
||||
appointmentAdapterList.clear();
|
||||
appointmentGrid.clear();
|
||||
for (int i = appointmentGrid.getRowCount() - 1; i >= 0; i--) {
|
||||
appointmentGrid.removeRow(i);
|
||||
}
|
||||
|
||||
|
||||
//Get the start date, make sure time is 0:00:00 AM
|
||||
Date startDate = (Date) calendarWidget.getDate().clone();
|
||||
Date today = new Date();
|
||||
Date endDate = (Date) calendarWidget.getDate().clone();
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
DateUtils.resetTime(today);
|
||||
DateUtils.resetTime(startDate);
|
||||
DateUtils.resetTime(endDate);
|
||||
|
||||
int row = 0;
|
||||
|
||||
for (int i = 0; i < calendarWidget.getDays(); i++) {
|
||||
|
||||
// Filter the list by date
|
||||
List<Appointment> filteredList = AppointmentUtil
|
||||
.filterListByDate(calendarWidget.getAppointments(), startDate, endDate);
|
||||
|
||||
if (filteredList != null && filteredList.size() > 0) {
|
||||
|
||||
appointmentGrid.setText(row, 0, DEFAULT_DATE_FORMAT.format(startDate));
|
||||
|
||||
appointmentGrid.getCellFormatter().setVerticalAlignment(row, 0,
|
||||
HasVerticalAlignment.ALIGN_TOP);
|
||||
appointmentGrid.getFlexCellFormatter().setRowSpan(row, 0,
|
||||
filteredList.size());
|
||||
appointmentGrid.getFlexCellFormatter().setStyleName(row, 0,
|
||||
"dateCell");
|
||||
int startingCell = 1;
|
||||
|
||||
//Row styles will alternate, so we set the style accordingly
|
||||
String rowStyle = (i % 2 == 0) ? "row" : "row-alt";
|
||||
|
||||
//If a Row represents the current date (Today) then we style it differently
|
||||
if (startDate.equals(today))
|
||||
rowStyle += "-today";
|
||||
|
||||
|
||||
for (Appointment appt : filteredList) {
|
||||
|
||||
// add the time range
|
||||
String timeSpanString = DEFAULT_TIME_FORMAT.format(appt.getStart())
|
||||
+ " - " + DEFAULT_TIME_FORMAT.format(appt.getEnd());
|
||||
Label timeSpanLabel = new Label(timeSpanString.toLowerCase());
|
||||
appointmentGrid.setWidget(row, startingCell, timeSpanLabel);
|
||||
|
||||
|
||||
|
||||
// add the title and description
|
||||
FlowPanel titleContainer = new FlowPanel();
|
||||
InlineLabel titleLabel = new InlineLabel(appt.getTitle());
|
||||
titleContainer.add(titleLabel);
|
||||
InlineLabel descLabel = new InlineLabel(" - "
|
||||
+ appt.getDescription());
|
||||
descLabel.setStyleName("descriptionLabel");
|
||||
titleContainer.add(descLabel);
|
||||
appointmentGrid.setWidget(row, startingCell + 1,
|
||||
titleContainer);
|
||||
|
||||
|
||||
|
||||
SimplePanel detailContainerPanel = new SimplePanel();
|
||||
AppointmentDetailPanel detailContainer= new AppointmentDetailPanel(detailContainerPanel, appt);
|
||||
|
||||
appointmentAdapterList.add(new AgendaViewAppointmentAdapter(
|
||||
titleLabel, timeSpanLabel, detailContainerPanel,
|
||||
detailContainer.getMoreDetailsLabel(), appt));
|
||||
|
||||
//add the detail container
|
||||
titleContainer.add(detailContainer);
|
||||
|
||||
//add click handlers to title, date and details link
|
||||
timeSpanLabel.addClickHandler(appointmentClickHandler);
|
||||
titleLabel.addClickHandler(appointmentClickHandler);
|
||||
detailContainer.getMoreDetailsLabel().addClickHandler(
|
||||
appointmentClickHandler);
|
||||
|
||||
|
||||
|
||||
|
||||
// Format the Cells
|
||||
appointmentGrid.getCellFormatter().setVerticalAlignment(
|
||||
row, startingCell, HasVerticalAlignment.ALIGN_TOP);
|
||||
appointmentGrid.getCellFormatter().setVerticalAlignment(
|
||||
row, startingCell + 1,
|
||||
HasVerticalAlignment.ALIGN_TOP);
|
||||
appointmentGrid.getCellFormatter().setStyleName(row,
|
||||
startingCell, "timeCell");
|
||||
appointmentGrid.getCellFormatter().setStyleName(row,
|
||||
startingCell + 1, "titleCell");
|
||||
appointmentGrid.getRowFormatter().setStyleName(row,
|
||||
rowStyle);
|
||||
|
||||
// increment the row
|
||||
// make sure the starting column is reset to 0
|
||||
startingCell = 0;
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
// increment the date
|
||||
startDate.setDate(startDate.getDate() + 1);
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handles appointments being clicked. Based on the clicked widget will determine
|
||||
* exactly which appointment was clicked and may 1) expand / collaps the appointment
|
||||
* details 2) set the selected appointment or 3) trigger an appointment clicked
|
||||
* event.
|
||||
*/
|
||||
private ClickHandler appointmentClickHandler = new ClickHandler() {
|
||||
|
||||
public void onClick(ClickEvent event) {
|
||||
|
||||
//get the appointment adapter based on the clicked widget
|
||||
AgendaViewAppointmentAdapter adapter =
|
||||
getAppointmentFromClickedWidget((Widget)event.getSource());
|
||||
|
||||
if (adapter != null) {
|
||||
if(event.getSource().equals(adapter.getDetailsLabel())) {
|
||||
//set the selected appointment
|
||||
calendarWidget.setSelectedAppointment(adapter.getAppointment(), true);
|
||||
//setSelectedAppointment(adapter.getAppointment(),false);
|
||||
//calendarWidget.fireOpenEvent(adapter.getAppointment());
|
||||
} else {
|
||||
//expand the panel if it is not yet expended
|
||||
adapter.getDetailsPanel().setVisible(
|
||||
!adapter.getDetailsPanel().isVisible());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Given Widget w determine which appointment was clicked. This is necessary because
|
||||
* each appointment has 3 widgets that can be clicked - the title, date range and
|
||||
* description.
|
||||
* @param w Widget that was clicked.
|
||||
* @return Appointment mapped to that widget.
|
||||
*/
|
||||
protected AgendaViewAppointmentAdapter getAppointmentFromClickedWidget(Widget w) {
|
||||
for(AgendaViewAppointmentAdapter a : appointmentAdapterList) {
|
||||
if(w.equals(a.dateLabel) || w.equals(a.detailsLabel) ||
|
||||
w.equals(a.titleLabel) || w.equals(a.getDetailsPanel())) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDoubleClick(Element element, Event event) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSingleClick(Element element, Event event) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public void onMouseOver(Element element, Event event) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppointmentSelected(Appointment appt) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import static com.bradrydzewski.gwt.calendar.client.DateUtils.minutesSinceDayStarted;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
|
||||
/**
|
||||
* The Appointment Adapter is used to track the layout of an
|
||||
* {@link Appointment}. It adds additional fields required to
|
||||
* calculate layout that are used by the Layout Strategy classes.
|
||||
*
|
||||
* This adapter allows us to keep these fields outside of the
|
||||
* {@link Appointment} class and keep the layout computations' complexity
|
||||
* away from the user.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class AppointmentAdapter {
|
||||
|
||||
private Appointment appointment;
|
||||
private int cellStart;
|
||||
private int cellSpan;
|
||||
private int columnStart = -1;
|
||||
private int columnSpan;
|
||||
private int appointmentStart;
|
||||
private int appointmentEnd;
|
||||
private float cellPercentFill;
|
||||
private float cellPercentStart;
|
||||
private List<TimeBlock> intersectingBlocks;
|
||||
private float top;
|
||||
private float left;
|
||||
private float width;
|
||||
private float height;
|
||||
|
||||
public float getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public void setTop(float top) {
|
||||
this.top = top;
|
||||
}
|
||||
|
||||
public float getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public void setLeft(float left) {
|
||||
this.left = left;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(float width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(float height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public AppointmentAdapter(Appointment appointment) {
|
||||
this.appointment = appointment;
|
||||
this.appointmentStart = minutesSinceDayStarted(appointment.getStart());
|
||||
this.appointmentEnd = minutesSinceDayStarted(appointment.getEnd());
|
||||
this.intersectingBlocks = new ArrayList<TimeBlock>();
|
||||
}
|
||||
|
||||
public int getCellStart() {
|
||||
return cellStart;
|
||||
}
|
||||
|
||||
public void setCellStart(int cellStart) {
|
||||
this.cellStart = cellStart;
|
||||
}
|
||||
|
||||
public int getCellSpan() {
|
||||
return cellSpan;
|
||||
}
|
||||
|
||||
public void setCellSpan(int cellSpan) {
|
||||
this.cellSpan = cellSpan;
|
||||
}
|
||||
|
||||
public int getColumnStart() {
|
||||
return columnStart;
|
||||
}
|
||||
|
||||
public void setColumnStart(int columnStart) {
|
||||
this.columnStart = columnStart;
|
||||
}
|
||||
|
||||
public int getColumnSpan() {
|
||||
return columnSpan;
|
||||
}
|
||||
|
||||
public void setColumnSpan(int columnSpan) {
|
||||
this.columnSpan = columnSpan;
|
||||
}
|
||||
|
||||
public int getAppointmentStart() {
|
||||
return appointmentStart;
|
||||
}
|
||||
|
||||
public void setAppointmentStart(int appointmentStart) {
|
||||
this.appointmentStart = appointmentStart;
|
||||
}
|
||||
|
||||
public int getAppointmentEnd() {
|
||||
return appointmentEnd;
|
||||
}
|
||||
|
||||
public void setAppointmentEnd(int appointmentEnd) {
|
||||
this.appointmentEnd = appointmentEnd;
|
||||
}
|
||||
|
||||
public List<TimeBlock> getIntersectingBlocks() {
|
||||
return intersectingBlocks;
|
||||
}
|
||||
|
||||
public void setIntersectingBlocks(List<TimeBlock> intersectingBlocks) {
|
||||
this.intersectingBlocks = intersectingBlocks;
|
||||
}
|
||||
|
||||
public Appointment getAppointment() {
|
||||
return appointment;
|
||||
}
|
||||
|
||||
public float getCellPercentFill() {
|
||||
return cellPercentFill;
|
||||
}
|
||||
|
||||
public void setCellPercentFill(float cellPercentFill) {
|
||||
this.cellPercentFill = cellPercentFill;
|
||||
}
|
||||
|
||||
public float getCellPercentStart() {
|
||||
return cellPercentStart;
|
||||
}
|
||||
|
||||
public void setCellPercentStart(float cellPercentStart) {
|
||||
this.cellPercentStart = cellPercentStart;
|
||||
}
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.google.gwt.event.dom.client.HasAllMouseHandlers;
|
||||
import com.google.gwt.event.dom.client.MouseDownEvent;
|
||||
import com.google.gwt.event.dom.client.MouseDownHandler;
|
||||
import com.google.gwt.event.dom.client.MouseMoveEvent;
|
||||
import com.google.gwt.event.dom.client.MouseMoveHandler;
|
||||
import com.google.gwt.event.dom.client.MouseOutEvent;
|
||||
import com.google.gwt.event.dom.client.MouseOutHandler;
|
||||
import com.google.gwt.event.dom.client.MouseOverEvent;
|
||||
import com.google.gwt.event.dom.client.MouseOverHandler;
|
||||
import com.google.gwt.event.dom.client.MouseUpEvent;
|
||||
import com.google.gwt.event.dom.client.MouseUpHandler;
|
||||
import com.google.gwt.event.dom.client.MouseWheelEvent;
|
||||
import com.google.gwt.event.dom.client.MouseWheelHandler;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.ComplexPanel;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public class AppointmentWidget extends FlowPanel {
|
||||
|
||||
class Div extends ComplexPanel implements HasAllMouseHandlers {
|
||||
|
||||
public Div() {
|
||||
setElement(DOM.createDiv());
|
||||
}
|
||||
|
||||
public void add(Widget w) {
|
||||
super.add(w, getElement());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
|
||||
return addDomHandler(handler, MouseDownEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
|
||||
return addDomHandler(handler, MouseUpEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
|
||||
return addDomHandler(handler, MouseOutEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
|
||||
return addDomHandler(handler, MouseOverEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
|
||||
return addDomHandler(handler, MouseMoveEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseWheelHandler(
|
||||
MouseWheelHandler handler) {
|
||||
return addDomHandler(handler, MouseWheelEvent.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private String title;
|
||||
private String description;
|
||||
private Date start;
|
||||
private Date end;
|
||||
private boolean selected;
|
||||
private float top;
|
||||
private float left;
|
||||
private float width;
|
||||
private float height;
|
||||
private Widget headerPanel = new Div();
|
||||
private Panel bodyPanel = new SimplePanel();
|
||||
private Widget footerPanel = new Div();
|
||||
private Panel timelinePanel = new SimplePanel();
|
||||
private Panel timelineFillPanel = new SimplePanel();
|
||||
private boolean multiDay = false;
|
||||
private Appointment appointment;
|
||||
|
||||
public AppointmentWidget() {
|
||||
this.setStylePrimaryName("gwt-appointment");
|
||||
headerPanel.setStylePrimaryName("header");
|
||||
bodyPanel.setStylePrimaryName("body");
|
||||
footerPanel.setStylePrimaryName("footer");
|
||||
timelinePanel.setStylePrimaryName("timeline");
|
||||
timelineFillPanel.setStylePrimaryName("timeline-fill");
|
||||
|
||||
this.add(headerPanel);
|
||||
this.add(bodyPanel);
|
||||
this.add(footerPanel);
|
||||
this.add(timelinePanel);
|
||||
timelinePanel.add(timelineFillPanel);
|
||||
DOM.setStyleAttribute(this.getElement(), "position", "absolute");
|
||||
}
|
||||
|
||||
public Widget getBody() {
|
||||
return this.bodyPanel;
|
||||
}
|
||||
|
||||
public Widget getHeader() {
|
||||
return this.headerPanel;
|
||||
}
|
||||
|
||||
public Date getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(Date start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public Date getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(Date end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public float getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public void setTop(float top) {
|
||||
this.top = top;
|
||||
DOM.setStyleAttribute(this.getElement(), "top", top + "px");
|
||||
}
|
||||
|
||||
public float getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public void setLeft(float left) {
|
||||
this.left = left;
|
||||
DOM.setStyleAttribute(this.getElement(), "left", left + "%");
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(float width) {
|
||||
this.width = width;
|
||||
DOM.setStyleAttribute(this.getElement(), "width", width + "%");
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(float height) {
|
||||
this.height = height;
|
||||
DOM.setStyleAttribute(this.getElement(), "height", height + "px");
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
DOM.setInnerHTML(headerPanel.getElement(), title);
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
DOM.setInnerHTML(bodyPanel.getElement(), description);
|
||||
}
|
||||
|
||||
public void formatTimeline(float top, float height) {
|
||||
timelineFillPanel.setHeight(height + "%");
|
||||
DOM.setStyleAttribute(timelineFillPanel.getElement(), "top", top + "%");
|
||||
}
|
||||
|
||||
public int compareTo(AppointmentWidget appt) {
|
||||
// -1 0 1
|
||||
// less, equal, greater
|
||||
int compare = this.getStart().compareTo(appt.getStart());
|
||||
|
||||
if (compare == 0) {
|
||||
compare = appt.getEnd().compareTo(this.getEnd());
|
||||
}
|
||||
|
||||
return compare;
|
||||
}
|
||||
|
||||
public Widget getMoveHandle() {
|
||||
return headerPanel;
|
||||
}
|
||||
|
||||
public Widget getResizeHandle() {
|
||||
return footerPanel;
|
||||
}
|
||||
|
||||
public boolean isMultiDay() {
|
||||
return multiDay;
|
||||
}
|
||||
|
||||
public void setMultiDay(boolean isMultiDay) {
|
||||
this.multiDay = isMultiDay;
|
||||
}
|
||||
|
||||
public Appointment getAppointment() {
|
||||
return appointment;
|
||||
}
|
||||
|
||||
public void setAppointment(Appointment appointment) {
|
||||
this.appointment = appointment;
|
||||
|
||||
if (appointment.isReadOnly()) {
|
||||
this.remove(footerPanel);
|
||||
}
|
||||
}
|
||||
}
|
571
src/com/bradrydzewski/gwt/calendar/client/dayview/DayView.java
Normal file
571
src/com/bradrydzewski/gwt/calendar/client/dayview/DayView.java
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.allen_sauer.gwt.dnd.client.DragEndEvent;
|
||||
import com.allen_sauer.gwt.dnd.client.DragHandler;
|
||||
import com.allen_sauer.gwt.dnd.client.DragStartEvent;
|
||||
import com.allen_sauer.gwt.dnd.client.PickupDragController;
|
||||
import com.allen_sauer.gwt.dnd.client.VetoDragException;
|
||||
import com.allen_sauer.gwt.dnd.client.drop.DayViewDropController;
|
||||
import com.allen_sauer.gwt.dnd.client.drop.DayViewPickupDragController;
|
||||
import com.allen_sauer.gwt.dnd.client.drop.DayViewResizeController;
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarSettings.Click;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarView;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarWidget;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DaySelectionHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.WeekSelectionHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.AppointmentUtil;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Document;
|
||||
import com.google.gwt.dom.client.NativeEvent;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.Window;
|
||||
|
||||
public class DayView extends CalendarView {
|
||||
|
||||
private DayViewHeader dayViewHeader = null;
|
||||
private DayViewBody dayViewBody = null;
|
||||
private DayViewMultiDayBody multiViewBody = null;
|
||||
private DayViewLayoutStrategy layoutStrategy = null;
|
||||
|
||||
private final List<AppointmentWidget> appointmentWidgets = new ArrayList<AppointmentWidget>();
|
||||
/**
|
||||
* List of AppointmentAdapter objects that represent the currently selected
|
||||
* appointment.
|
||||
*/
|
||||
private List<AppointmentWidget> selectedAppointmentWidgets = new ArrayList<AppointmentWidget>();
|
||||
|
||||
private final DayViewStyleManager styleManager = GWT.create(DayViewStyleManager.class);
|
||||
|
||||
private DayViewResizeController resizeController = null;
|
||||
|
||||
private DayViewDropController dropController = null;
|
||||
|
||||
private PickupDragController dragController = null;
|
||||
|
||||
private DayViewResizeController proxyResizeController = null;
|
||||
|
||||
public DayView() {
|
||||
super();
|
||||
}
|
||||
|
||||
private int getMaxProxyHeight() {
|
||||
// For a comfortable use, the Proxy should be, top 2/3 (66%) of the view
|
||||
return (2 * (dayViewBody.getScrollPanel().getOffsetHeight() / 3));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void doLayout() {
|
||||
// PERFORM APPOINTMENT LAYOUT NOW
|
||||
final Date date = (Date) calendarWidget.getDate().clone();
|
||||
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
multiViewBody.setDays((Date) date.clone(), calendarWidget.getDays());
|
||||
}
|
||||
|
||||
dayViewHeader.setDays((Date) date.clone(), calendarWidget.getDays());
|
||||
dayViewHeader.setYear((Date) date.clone());
|
||||
dayViewBody.setDays((Date) date.clone(), calendarWidget.getDays());
|
||||
dayViewBody.getTimeline().prepare();
|
||||
|
||||
dropController.setColumns(calendarWidget.getDays());
|
||||
dropController.setIntervalsPerHour(calendarWidget.getSettings().getIntervalsPerHour());
|
||||
dropController.setDayStartsAt(getSettings().getDayStartsAt());
|
||||
dropController.setDate((Date)calendarWidget.getDate().clone());
|
||||
dropController.setSnapSize(
|
||||
calendarWidget.getSettings().getPixelsPerInterval());
|
||||
dropController.setMaxProxyHeight(getMaxProxyHeight());
|
||||
resizeController.setIntervalsPerHour(
|
||||
calendarWidget.getSettings().getIntervalsPerHour());
|
||||
resizeController.setDayStartsAt(getSettings().getDayStartsAt());
|
||||
resizeController.setSnapSize(
|
||||
calendarWidget.getSettings().getPixelsPerInterval());
|
||||
proxyResizeController.setSnapSize(calendarWidget.getSettings().getPixelsPerInterval());
|
||||
proxyResizeController.setIntervalsPerHour(calendarWidget.getSettings().getIntervalsPerHour());
|
||||
proxyResizeController.setDayStartsAt(getSettings().getDayStartsAt());
|
||||
|
||||
this.selectedAppointmentWidgets.clear();
|
||||
appointmentWidgets.clear();
|
||||
|
||||
// HERE IS WHERE WE DO THE LAYOUT
|
||||
Date startDate = (Date) calendarWidget.getDate().clone();
|
||||
Date endDate = (Date) calendarWidget.getDate().clone();
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
DateUtils.resetTime(startDate);
|
||||
DateUtils.resetTime(endDate);
|
||||
|
||||
startDate.setHours(startDate.getHours());
|
||||
endDate.setHours(endDate.getHours());
|
||||
|
||||
for (int i = 0; i < calendarWidget.getDays(); i++) {
|
||||
|
||||
List<Appointment> filteredList = AppointmentUtil
|
||||
.filterListByDate(calendarWidget.getAppointments(), startDate, endDate);
|
||||
|
||||
// perform layout
|
||||
List<AppointmentAdapter> appointmentAdapters = layoutStrategy
|
||||
.doLayout(filteredList, i, calendarWidget.getDays());
|
||||
|
||||
// add all appointments back to the grid
|
||||
addAppointmentsToGrid(appointmentAdapters, false);
|
||||
|
||||
startDate.setDate(startDate.getDate() + 1);
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
}
|
||||
|
||||
List<Appointment> filteredList =
|
||||
AppointmentUtil.filterListByDateRange(calendarWidget.getAppointments(),
|
||||
calendarWidget.getDate(), calendarWidget.getDays());
|
||||
|
||||
ArrayList<AppointmentAdapter> adapterList = new ArrayList<AppointmentAdapter>();
|
||||
int desiredHeight = layoutStrategy.doMultiDayLayout(filteredList,
|
||||
adapterList, calendarWidget.getDate(), calendarWidget.getDays());
|
||||
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
multiViewBody.grid.setHeight(desiredHeight + "px");
|
||||
|
||||
addAppointmentsToGrid(adapterList, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the Appointments to the view.
|
||||
* @param appointmentList List of Appointments
|
||||
* @param addToMultiView <code>true</code> if is adding the appointments to the multiview section, <code>false</code> otherwise
|
||||
*/
|
||||
private void addAppointmentsToGrid(final List<AppointmentAdapter> appointmentList, final boolean addToMultiView) {
|
||||
for (AppointmentAdapter appt : appointmentList) {
|
||||
AppointmentWidget panel = new AppointmentWidget();
|
||||
panel.setWidth(appt.getWidth());
|
||||
panel.setHeight(appt.getHeight());
|
||||
panel.setTitle(appt.getAppointment().getTitle());
|
||||
panel.setTop(appt.getTop());
|
||||
panel.setLeft(appt.getLeft());
|
||||
panel.setAppointment(appt.getAppointment());
|
||||
|
||||
boolean selected = calendarWidget.isTheSelectedAppointment(panel
|
||||
.getAppointment());
|
||||
if (selected) {
|
||||
selectedAppointmentWidgets.add(panel);
|
||||
}
|
||||
styleManager.applyStyle(panel, selected);
|
||||
appointmentWidgets.add(panel);
|
||||
|
||||
if (addToMultiView) {
|
||||
panel.setMultiDay(true);
|
||||
this.multiViewBody.grid.add(panel);
|
||||
} else {
|
||||
panel.setDescription(appt.getAppointment().getDescription());
|
||||
dayViewBody.getGrid().grid.add(panel);
|
||||
|
||||
//make footer 'draggable'
|
||||
if (calendarWidget.getSettings().isEnableDragDrop() && !appt.getAppointment().isReadOnly()) {
|
||||
resizeController.makeDraggable(panel.getResizeHandle());
|
||||
dragController.makeDraggable(panel, panel.getMoveHandle());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollToHour(final int hour) {
|
||||
dayViewBody.getScrollPanel().setVerticalScrollPosition((hour - getSettings().getDayStartsAt()) *
|
||||
getSettings().getIntervalsPerHour() * getSettings().getPixelsPerInterval());
|
||||
}
|
||||
|
||||
public void doSizing() {
|
||||
|
||||
if (calendarWidget.getOffsetHeight() > 0) {
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
dayViewBody.setHeight(calendarWidget.getOffsetHeight() - 2
|
||||
- dayViewHeader.getOffsetHeight()
|
||||
- multiViewBody.getOffsetHeight() + "px");
|
||||
} else {
|
||||
dayViewBody.setHeight(calendarWidget.getOffsetHeight() - 2
|
||||
- dayViewHeader.getOffsetHeight() + "px");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeleteKeyPressed() {
|
||||
if (calendarWidget.getSelectedAppointment() != null) {
|
||||
calendarWidget.fireDeleteEvent(calendarWidget.getSelectedAppointment());
|
||||
}
|
||||
}
|
||||
|
||||
public void onDoubleClick(Element element, Event event) {
|
||||
|
||||
List<AppointmentWidget> list = findAppointmentWidgetsByElement(element);
|
||||
if (!list.isEmpty()) {
|
||||
Appointment appt = list.get(0).getAppointment();
|
||||
//if (appt.equals(calendarWidget.getSelectedAppointment()))
|
||||
calendarWidget.fireOpenEvent(appt);
|
||||
// exit out
|
||||
} else if (getSettings().getTimeBlockClickNumber() == Click.Double
|
||||
&& element == dayViewBody.getGrid().gridOverlay.getElement()) {
|
||||
int x = DOM.eventGetClientX(event) + Window.getScrollLeft();
|
||||
int y = DOM.eventGetClientY(event) + Window.getScrollTop();
|
||||
timeBlockClick(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void onSingleClick(final Element element, final Event event) {
|
||||
|
||||
// Ignore the scroll panel
|
||||
if (dayViewBody.getScrollPanel().getElement().equals(element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Appointment appointment = findAppointmentByElement(element);
|
||||
|
||||
if (appointment != null) {
|
||||
selectAppointment(appointment);
|
||||
} else if ((getSettings().getTimeBlockClickNumber() == Click.Single
|
||||
|| getSettings().getTimeBlockClickNumber() == Click.Drag)
|
||||
&& element == dayViewBody.getGrid().gridOverlay
|
||||
.getElement()) {
|
||||
int x = DOM.eventGetClientX(event) + Window.getScrollLeft();
|
||||
int y = DOM.eventGetClientY(event) + Window.getScrollTop();
|
||||
timeBlockClick(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void onMouseOver(final Element element, final Event event) {
|
||||
Appointment appointment = findAppointmentByElement(element);
|
||||
calendarWidget.fireMouseOverEvent(appointment, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppointmentSelected(Appointment appointment) {
|
||||
|
||||
List<AppointmentWidget> clickedAppointmentAdapters =
|
||||
findAppointmentWidget(appointment);
|
||||
|
||||
if (!clickedAppointmentAdapters.isEmpty()) {
|
||||
for (AppointmentWidget adapter : selectedAppointmentWidgets) {
|
||||
styleManager.applyStyle(adapter, false);
|
||||
}
|
||||
|
||||
for (AppointmentWidget adapter : clickedAppointmentAdapters) {
|
||||
styleManager.applyStyle(adapter, true);
|
||||
}
|
||||
|
||||
selectedAppointmentWidgets.clear();
|
||||
selectedAppointmentWidgets = clickedAppointmentAdapters;
|
||||
|
||||
float height = clickedAppointmentAdapters.get(0).getHeight();
|
||||
// scrollIntoView ONLY if the appointment fits in the viewable area
|
||||
if (dayViewBody.getScrollPanel().getOffsetHeight() > height) {
|
||||
DOM.scrollIntoView(clickedAppointmentAdapters.get(0).getElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onRightArrowKeyPressed() {
|
||||
calendarWidget.selectNextAppointment();
|
||||
}
|
||||
|
||||
public void onUpArrowKeyPressed() {
|
||||
calendarWidget.selectPreviousAppointment();
|
||||
}
|
||||
|
||||
public void onDownArrowKeyPressed() {
|
||||
calendarWidget.selectNextAppointment();
|
||||
}
|
||||
|
||||
public void onLeftArrowKeyPressed() {
|
||||
calendarWidget.selectPreviousAppointment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStyleName() {
|
||||
return "gwt-cal";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach(CalendarWidget widget) {
|
||||
super.attach(widget);
|
||||
|
||||
if (dayViewBody == null) {
|
||||
dayViewBody = new DayViewBody(this);
|
||||
dayViewHeader = new DayViewHeader(this);
|
||||
layoutStrategy = new DayViewLayoutStrategy(this);
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
multiViewBody = new DayViewMultiDayBody(this);
|
||||
}
|
||||
}
|
||||
|
||||
calendarWidget.getRootPanel().add(dayViewHeader);
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
calendarWidget.getRootPanel().add(multiViewBody);
|
||||
}
|
||||
calendarWidget.getRootPanel().add(dayViewBody);
|
||||
|
||||
if (getSettings() != null) {
|
||||
scrollToHour(getSettings().getScrollToHour());
|
||||
}
|
||||
|
||||
// Creates the different Controllers, if needed
|
||||
createDragController();
|
||||
createDropController();
|
||||
createResizeController();
|
||||
}
|
||||
|
||||
private void createDragController() {
|
||||
if (dragController == null) {
|
||||
dragController = new DayViewPickupDragController(dayViewBody.getGrid().grid, false);
|
||||
dragController.setBehaviorDragProxy(true);
|
||||
dragController.setBehaviorDragStartSensitivity(1);
|
||||
dragController.setBehaviorConstrainedToBoundaryPanel(true); //do I need these?
|
||||
dragController.setConstrainWidgetToBoundaryPanel(true); //do I need these?
|
||||
dragController.setBehaviorMultipleSelection(false);
|
||||
dragController.addDragHandler(new DragHandler(){
|
||||
|
||||
public void onDragEnd(DragEndEvent event) {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable).getAppointment();
|
||||
calendarWidget.setCommittedAppointment(appt);
|
||||
calendarWidget.fireUpdateEvent(appt);
|
||||
}
|
||||
|
||||
public void onDragStart(DragStartEvent event) {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable).getAppointment();
|
||||
calendarWidget.setRollbackAppointment(appt.clone());
|
||||
((DayViewPickupDragController)dragController).setMaxProxyHeight(getMaxProxyHeight());
|
||||
}
|
||||
|
||||
public void onPreviewDragEnd(DragEndEvent event)
|
||||
throws VetoDragException {
|
||||
}
|
||||
|
||||
public void onPreviewDragStart(DragStartEvent event)
|
||||
throws VetoDragException {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void createDropController() {
|
||||
if (dropController==null) {
|
||||
dropController = new DayViewDropController(dayViewBody.getGrid().grid);
|
||||
dragController.registerDropController(dropController);
|
||||
}
|
||||
}
|
||||
|
||||
private void createResizeController() {
|
||||
if (resizeController == null) {
|
||||
resizeController = new DayViewResizeController(dayViewBody.getGrid().grid);
|
||||
resizeController.addDragHandler(new DragHandler(){
|
||||
|
||||
public void onDragEnd(DragEndEvent event) {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable.getParent()).getAppointment();
|
||||
calendarWidget.setCommittedAppointment(appt);
|
||||
calendarWidget.fireUpdateEvent(appt);
|
||||
}
|
||||
|
||||
public void onDragStart(DragStartEvent event) {
|
||||
calendarWidget
|
||||
.setRollbackAppointment(((AppointmentWidget) event
|
||||
.getContext().draggable.getParent()).getAppointment()
|
||||
.clone());
|
||||
}
|
||||
|
||||
public void onPreviewDragEnd(DragEndEvent event)
|
||||
throws VetoDragException {}
|
||||
public void onPreviewDragStart(DragStartEvent event)
|
||||
throws VetoDragException {}
|
||||
});
|
||||
}
|
||||
|
||||
if(proxyResizeController == null) {
|
||||
proxyResizeController = new DayViewResizeController(dayViewBody.getGrid().grid);
|
||||
proxyResizeController.addDragHandler(new DragHandler(){
|
||||
long startTime = 0L;
|
||||
int initialX = 0;
|
||||
int initialY = 0;
|
||||
Date startDate;
|
||||
|
||||
public void onDragEnd(DragEndEvent event) {
|
||||
long clickTime = System.currentTimeMillis() - startTime;
|
||||
int y = event.getContext().mouseY;
|
||||
if (clickTime <= 500 && initialY == y) {
|
||||
calendarWidget.fireTimeBlockClickEvent(startDate);
|
||||
} else {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable.getParent()).getAppointment();
|
||||
calendarWidget.setCommittedAppointment(appt);
|
||||
calendarWidget.fireCreateEvent(appt);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDragStart(DragStartEvent event) {
|
||||
startTime = System.currentTimeMillis();
|
||||
initialX = event.getContext().mouseX;
|
||||
initialY = event.getContext().mouseY;
|
||||
startDate = getCoordinatesDate(initialX, initialY);
|
||||
calendarWidget.setRollbackAppointment(null);
|
||||
}
|
||||
|
||||
public void onPreviewDragEnd(DragEndEvent event)
|
||||
throws VetoDragException {}
|
||||
public void onPreviewDragStart(DragStartEvent event)
|
||||
throws VetoDragException {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private Date getCoordinatesDate(int x, int y) {
|
||||
int left = dayViewBody.getGrid().gridOverlay.getAbsoluteLeft();
|
||||
int top = dayViewBody.getScrollPanel().getAbsoluteTop();
|
||||
int width = dayViewBody.getGrid().gridOverlay.getOffsetWidth();
|
||||
int scrollOffset = dayViewBody.getScrollPanel().getVerticalScrollPosition();
|
||||
|
||||
// x & y are based on screen position,need to get x/y relative to
|
||||
// component
|
||||
int relativeY = y - top + scrollOffset;
|
||||
int relativeX = x - left;
|
||||
|
||||
// find the interval clicked and day clicked
|
||||
double interval = Math.floor(relativeY
|
||||
/ (double) getSettings().getPixelsPerInterval());
|
||||
double day = Math.floor((double) relativeX
|
||||
/ ((double) width / (double) calendarWidget.getDays()));
|
||||
|
||||
// create new appointment date based on click
|
||||
Date newStartDate = calendarWidget.getDate();
|
||||
newStartDate.setHours(getSettings().getDayStartsAt());
|
||||
newStartDate.setMinutes(0);
|
||||
newStartDate.setSeconds(0);
|
||||
newStartDate.setMinutes((int) interval
|
||||
* (60 / getSettings().getIntervalsPerHour()));
|
||||
newStartDate.setDate(newStartDate.getDate() + (int) day);
|
||||
|
||||
return newStartDate;
|
||||
}
|
||||
|
||||
private void timeBlockClick(int x, int y) {
|
||||
int left = dayViewBody.getGrid().gridOverlay.getAbsoluteLeft();
|
||||
int top = dayViewBody.getScrollPanel().getAbsoluteTop();
|
||||
int width = dayViewBody.getGrid().gridOverlay.getOffsetWidth();
|
||||
int scrollOffset = dayViewBody.getScrollPanel().getVerticalScrollPosition();
|
||||
|
||||
// x & y are based on screen position,need to get x/y relative to
|
||||
// component
|
||||
int relativeY = y - top + scrollOffset;
|
||||
int relativeX = x - left;
|
||||
|
||||
// find the interval clicked and day clicked
|
||||
double day = Math.floor((double) relativeX
|
||||
/ ((double) width / (double) calendarWidget.getDays()));
|
||||
|
||||
Date newStartDate = getCoordinatesDate(x, y);
|
||||
|
||||
if (getSettings().getTimeBlockClickNumber() != Click.Drag) {
|
||||
calendarWidget.fireTimeBlockClickEvent(newStartDate);
|
||||
} else {
|
||||
int snapSize = calendarWidget.getSettings().getPixelsPerInterval();
|
||||
// Create the proxy
|
||||
width = width / calendarWidget.getDays();
|
||||
left = (int) day * width;
|
||||
// Adjust the start to the closest interval
|
||||
top = (int)Math.floor(
|
||||
(float) relativeY / snapSize) * snapSize;
|
||||
|
||||
AppointmentWidget proxy = new AppointmentWidget();
|
||||
Appointment app = new Appointment();
|
||||
app.setStart(newStartDate);
|
||||
app.setEnd(newStartDate);
|
||||
proxy.setAppointment(app);
|
||||
proxy.setStart(newStartDate);
|
||||
proxy.setPixelSize(width, /*height*/ snapSize);
|
||||
dayViewBody.getGrid().grid.add(proxy, left, top);
|
||||
styleManager.applyStyle(proxy, false);
|
||||
proxyResizeController.makeDraggable(proxy.getResizeHandle());
|
||||
|
||||
NativeEvent evt = Document.get().createMouseDownEvent(1, 0, 0, x, y, false,
|
||||
false, false, false, NativeEvent.BUTTON_LEFT);
|
||||
proxy.getResizeHandle().getElement().dispatchEvent(evt);
|
||||
}
|
||||
}
|
||||
|
||||
private List<AppointmentWidget> findAppointmentWidgetsByElement(
|
||||
Element element) {
|
||||
return findAppointmentWidget(findAppointmentByElement(element));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Appointment} indirectly associated to the passed
|
||||
* <code>element</code>. Each Appointment drawn on the CalendarView maps to
|
||||
* a Widget and therefore an Element. This method attempts to find an
|
||||
* Appointment based on the provided Element. If no match is found a null
|
||||
* value is returned.
|
||||
*
|
||||
* @param element
|
||||
* Element to look up.
|
||||
* @return Appointment matching the element.
|
||||
*/
|
||||
private Appointment findAppointmentByElement(Element element) {
|
||||
Appointment appointmentAtElement = null;
|
||||
for (AppointmentWidget widget : appointmentWidgets) {
|
||||
if (DOM.isOrHasChild(widget.getElement(), element)) {
|
||||
appointmentAtElement = widget.getAppointment();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return appointmentAtElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds any related adapters that match the given Appointment.
|
||||
*
|
||||
* @param appt
|
||||
* Appointment to match.
|
||||
* @return List of related AppointmentWidget objects.
|
||||
*/
|
||||
private List<AppointmentWidget> findAppointmentWidget(Appointment appt) {
|
||||
ArrayList<AppointmentWidget> appointmentAdapters = new ArrayList<AppointmentWidget>();
|
||||
if (appt != null) {
|
||||
for (AppointmentWidget widget : appointmentWidgets) {
|
||||
if (widget.getAppointment().equals(appt)) {
|
||||
appointmentAdapters.add(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
return appointmentAdapters;
|
||||
}
|
||||
|
||||
public HandlerRegistration addWeekSelectionHandler(
|
||||
WeekSelectionHandler<Date> handler) {
|
||||
return dayViewHeader.addWeekSelectionHandler(handler);
|
||||
}
|
||||
|
||||
public HandlerRegistration addDaySelectionHandler(
|
||||
DaySelectionHandler<Date> handler) {
|
||||
return dayViewHeader.addDaySelectionHandler(handler);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment.VerticalAlignmentConstant;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public class DayViewBody extends Composite {
|
||||
private FlexTable layout = new FlexTable();
|
||||
private ScrollPanel scrollPanel = new ScrollPanel();
|
||||
private DayViewTimeline timeline = null;
|
||||
private DayViewGrid grid = null;
|
||||
private HasSettings settings = null;
|
||||
|
||||
public void add(Widget w) {
|
||||
scrollPanel.add(w);
|
||||
}
|
||||
|
||||
public ScrollPanel getScrollPanel() {
|
||||
return scrollPanel;
|
||||
}
|
||||
|
||||
public DayViewGrid getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public DayViewTimeline getTimeline() {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
public DayViewGrid getDayViewGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public DayViewTimeline getDayViewTimeline() {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
public DayViewBody(HasSettings settings) {
|
||||
initWidget(scrollPanel);
|
||||
this.settings = settings;
|
||||
this.timeline = new DayViewTimeline(settings);
|
||||
this.grid = new DayViewGrid(settings);
|
||||
scrollPanel.setStylePrimaryName("scroll-area");
|
||||
DOM.setStyleAttribute(scrollPanel.getElement(), "overflowX",
|
||||
"hidden");
|
||||
DOM.setStyleAttribute(scrollPanel.getElement(), "overflowY",
|
||||
"scroll");
|
||||
|
||||
// create the calendar body layout table
|
||||
// calendarBodyLayoutTable.setStyleName("scroll-area");
|
||||
layout.setCellPadding(0);
|
||||
layout.setBorderWidth(0);
|
||||
layout.setCellSpacing(0);
|
||||
layout.getColumnFormatter().setWidth(1, "99%");
|
||||
// set vertical alignment
|
||||
VerticalAlignmentConstant valign = HasVerticalAlignment.ALIGN_TOP;
|
||||
layout.getCellFormatter().setVerticalAlignment(0, 0, valign);
|
||||
layout.getCellFormatter().setVerticalAlignment(0, 1, valign);
|
||||
|
||||
grid.setStyleName("gwt-appointment-panel");
|
||||
|
||||
//TODO: use CSS to set table layout
|
||||
layout.getCellFormatter().setWidth(0, 0, "50px");
|
||||
DOM.setStyleAttribute(layout.getElement(), "tableLayout", "fixed");
|
||||
|
||||
layout.setWidget(0, 0, timeline);
|
||||
layout.setWidget(0, 1, grid);
|
||||
scrollPanel.add(layout);
|
||||
|
||||
}
|
||||
|
||||
public void setDays(Date date, int days) {
|
||||
grid.build(settings.getSettings().getWorkingHourStart(),
|
||||
settings.getSettings().getWorkingHourEnd(), days);
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.FormattingUtil;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.ComplexPanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
/**
|
||||
* The DayGrid draws the grid that displays days / time intervals in the
|
||||
* body of the calendar.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class DayViewGrid /*Impl*/ extends Composite {
|
||||
|
||||
class Div extends ComplexPanel {
|
||||
|
||||
public Div() {
|
||||
setElement(DOM.createDiv());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Widget w) {
|
||||
return super.remove(w);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Widget w) {
|
||||
super.add(w, getElement());
|
||||
}
|
||||
}
|
||||
|
||||
protected AbsolutePanel grid = new AbsolutePanel();
|
||||
protected SimplePanel gridOverlay = new SimplePanel();
|
||||
|
||||
private HasSettings settings = null;
|
||||
|
||||
private static final int HOURS_PER_DAY = 24;
|
||||
|
||||
public DayViewGrid(HasSettings settings) { //was DayViewGridImpl
|
||||
initWidget(grid);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public void build(int workingHourStart, int workingHourStop, int days) {
|
||||
|
||||
grid.clear();
|
||||
|
||||
int intervalsPerHour = settings.getSettings().getIntervalsPerHour(); //2; //30 minute intervals
|
||||
float intervalSize = settings.getSettings().getPixelsPerInterval();
|
||||
|
||||
this.setHeight((intervalsPerHour * (intervalSize) * 24) + "px");
|
||||
|
||||
float dayWidth = 100f / days;
|
||||
float dayLeft = 0f;
|
||||
|
||||
int dayStartsAt = settings.getSettings().getDayStartsAt();
|
||||
|
||||
for (int i = 0; i < HOURS_PER_DAY; i++) {
|
||||
boolean isWorkingHours = ((i + dayStartsAt) >= workingHourStart && (i + dayStartsAt) <= workingHourStop);
|
||||
//create major interval
|
||||
SimplePanel sp1 = new SimplePanel();
|
||||
sp1.setStyleName("major-time-interval");
|
||||
sp1.setHeight(intervalSize + FormattingUtil.getBorderOffset() + "px");
|
||||
|
||||
//if working hours set
|
||||
if (isWorkingHours) {
|
||||
sp1.addStyleName("working-hours");
|
||||
}
|
||||
|
||||
//add to body
|
||||
grid.add(sp1);
|
||||
|
||||
for (int x = 0; x < intervalsPerHour - 1; x++) {
|
||||
SimplePanel sp2 = new SimplePanel();
|
||||
sp2.setStyleName("minor-time-interval");
|
||||
|
||||
sp2.setHeight(intervalSize + FormattingUtil.getBorderOffset() + "px");
|
||||
if (isWorkingHours) {
|
||||
sp2.addStyleName("working-hours");
|
||||
}
|
||||
grid.add(sp2);
|
||||
}
|
||||
}
|
||||
|
||||
for (int day = 0; day < days; day++) {
|
||||
dayLeft = dayWidth * day;
|
||||
SimplePanel dayPanel = new SimplePanel();
|
||||
dayPanel.setStyleName("day-separator");
|
||||
grid.add(dayPanel);
|
||||
DOM.setStyleAttribute(dayPanel.getElement(), "left", dayLeft + "%");
|
||||
}
|
||||
|
||||
gridOverlay.setHeight("100%");
|
||||
gridOverlay.setWidth("100%");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "position", "absolute");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "left", "0px");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "top", "0px");
|
||||
grid.add(gridOverlay);
|
||||
}
|
||||
}
|
@ -0,0 +1,220 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarFormat;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DaySelectionEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DaySelectionHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasDaySelectionHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasWeekSelectionHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.WeekSelectionEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.WeekSelectionHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.WindowUtils;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
|
||||
public class DayViewHeader extends Composite implements HasWeekSelectionHandlers<Date>, HasDaySelectionHandlers<Date> {
|
||||
private FlexTable header = new FlexTable();
|
||||
private VerticalPanel timePanel = new VerticalPanel();
|
||||
private AbsolutePanel dayPanel = new AbsolutePanel();
|
||||
private AbsolutePanel weekPanel = new AbsolutePanel();
|
||||
private AbsolutePanel splitter = new AbsolutePanel();
|
||||
private static final String GWT_CALENDAR_HEADER_STYLE = "gwt-calendar-header";
|
||||
private static final String DAY_CELL_CONTAINER_STYLE = "day-cell-container";
|
||||
private static final String WEEK_CELL_CONTAINER_STYLE = "week-cell-container";
|
||||
private static final String YEAR_CELL_STYLE = "year-cell";
|
||||
private static final String SPLITTER_STYLE = "splitter";
|
||||
private final boolean showWeekNumbers;
|
||||
private final HasSettings settings;
|
||||
|
||||
public DayViewHeader(HasSettings settings) {
|
||||
initWidget(header);
|
||||
|
||||
this.settings = settings;
|
||||
|
||||
header.setStyleName(GWT_CALENDAR_HEADER_STYLE);
|
||||
dayPanel.setStyleName(DAY_CELL_CONTAINER_STYLE);
|
||||
weekPanel.setStyleName(WEEK_CELL_CONTAINER_STYLE);
|
||||
timePanel.setWidth("100%");
|
||||
|
||||
showWeekNumbers = settings.getSettings().isShowingWeekNumbers();
|
||||
|
||||
header.insertRow(0);
|
||||
header.insertRow(0);
|
||||
header.insertCell(0, 0);
|
||||
header.insertCell(0, 0);
|
||||
header.insertCell(0, 0);
|
||||
header.setWidget(0, 1, timePanel);
|
||||
header.getCellFormatter().setStyleName(0, 0, YEAR_CELL_STYLE);
|
||||
header.getCellFormatter().setWidth(0, 2,
|
||||
WindowUtils.getScrollBarWidth(true) + "px");
|
||||
|
||||
header.getFlexCellFormatter().setColSpan(1, 0, 3);
|
||||
header.setCellPadding(0);
|
||||
header.setBorderWidth(0);
|
||||
header.setCellSpacing(0);
|
||||
|
||||
if (showWeekNumbers) {
|
||||
timePanel.add(weekPanel);
|
||||
}
|
||||
timePanel.add(dayPanel);
|
||||
|
||||
splitter.setStylePrimaryName(SPLITTER_STYLE);
|
||||
header.setWidget(1, 0, splitter);
|
||||
}
|
||||
|
||||
public void setDays(Date date, int days) {
|
||||
|
||||
dayPanel.clear();
|
||||
weekPanel.clear();
|
||||
|
||||
float dayWidth = 100f / days;
|
||||
float dayLeft;
|
||||
int week = DateUtils.calendarWeekIso(date);
|
||||
int previousDayWeek = week;
|
||||
Date previousDate = date;
|
||||
float weekWidth = 0f;
|
||||
float weekLeft = 0f;
|
||||
|
||||
for (int i = 0; i < days; i++) {
|
||||
|
||||
// set the left position of the day splitter to
|
||||
// the width * incremented value
|
||||
dayLeft = dayWidth * i;
|
||||
|
||||
// increment the date by 1
|
||||
if (i > 0) {
|
||||
DateUtils.moveOneDayForward(date);
|
||||
} else {
|
||||
// initialize the week values
|
||||
weekLeft = dayLeft;
|
||||
weekWidth = dayWidth;
|
||||
}
|
||||
|
||||
String headerTitle = CalendarFormat.INSTANCE.getDateFormat().format(date);
|
||||
|
||||
Label dayLabel = new Label();
|
||||
dayLabel.setStylePrimaryName("day-cell");
|
||||
dayLabel.setWidth(dayWidth + "%");
|
||||
dayLabel.setText(headerTitle);
|
||||
DOM.setStyleAttribute(dayLabel.getElement(), "left", dayLeft + "%");
|
||||
|
||||
addDayClickHandler(dayLabel, (Date) date.clone());
|
||||
|
||||
boolean found = false;
|
||||
for (Date day : settings.getSettings().getHolidays()) {
|
||||
if (DateUtils.areOnTheSameDay(day, date)) {
|
||||
dayLabel.setStyleName("day-cell-holiday");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// set the style of the header to show that it is today
|
||||
if (DateUtils.areOnTheSameDay(new Date(), date)) {
|
||||
dayLabel.setStyleName("day-cell-today");
|
||||
} else if (!found && DateUtils.isWeekend(date)) {
|
||||
dayLabel.setStyleName("day-cell-weekend");
|
||||
}
|
||||
|
||||
if (showWeekNumbers) {
|
||||
week = DateUtils.calendarWeekIso(date);
|
||||
boolean lastDay = i + 1 == days;
|
||||
if ((previousDayWeek != week) || lastDay) {
|
||||
if (lastDay) {
|
||||
previousDayWeek = week;
|
||||
previousDate = date;
|
||||
}
|
||||
String weekTitle = "W " + previousDayWeek;
|
||||
|
||||
Label weekLabel = new Label();
|
||||
weekLabel.setStylePrimaryName("week-cell");
|
||||
weekLabel.setWidth(weekWidth + "%");
|
||||
weekLabel.setText(weekTitle);
|
||||
DOM.setStyleAttribute(weekLabel.getElement(), "left", weekLeft + "%");
|
||||
|
||||
addWeekClickHandler(weekLabel, previousDate);
|
||||
|
||||
weekPanel.add(weekLabel);
|
||||
|
||||
weekWidth = dayWidth;
|
||||
weekLeft = dayLeft + dayWidth;
|
||||
} else {
|
||||
weekWidth += dayWidth;
|
||||
}
|
||||
previousDayWeek = week;
|
||||
previousDate = date;
|
||||
}
|
||||
|
||||
dayPanel.add(dayLabel);
|
||||
}
|
||||
}
|
||||
|
||||
public void setYear(Date date) {
|
||||
setYear(DateUtils.year(date));
|
||||
}
|
||||
|
||||
public void setYear(int year) {
|
||||
header.setText(0, 0, String.valueOf(year));
|
||||
}
|
||||
|
||||
private void addDayClickHandler(final Label dayLabel, final Date day) {
|
||||
dayLabel.addClickHandler(new ClickHandler() {
|
||||
public void onClick(ClickEvent event) {
|
||||
fireSelectedDay(day);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addWeekClickHandler(final Label weekLabel, final Date day) {
|
||||
weekLabel.addClickHandler(new ClickHandler() {
|
||||
public void onClick(ClickEvent event) {
|
||||
fireSelectedWeek(day);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fireSelectedDay(final Date day) {
|
||||
DaySelectionEvent.fire(this, day);
|
||||
}
|
||||
|
||||
private void fireSelectedWeek(final Date day) {
|
||||
WeekSelectionEvent.fire(this, day);
|
||||
}
|
||||
|
||||
public HandlerRegistration addWeekSelectionHandler(
|
||||
WeekSelectionHandler<Date> handler) {
|
||||
return addHandler(handler, WeekSelectionEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addDaySelectionHandler(
|
||||
DaySelectionHandler<Date> handler) {
|
||||
return addHandler(handler, DaySelectionEvent.getType());
|
||||
}
|
||||
}
|
@ -0,0 +1,439 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.AppointmentUtil;
|
||||
|
||||
/**
|
||||
* Responsible for arranging all Appointments, visually, on a screen in a manner
|
||||
* similar to the Microsoft Outlook / Windows Vista calendar.
|
||||
* See: <img src='http://www.microsoft.com/library/media/1033/athome/images/moredone/calendar.gif'/>
|
||||
* <p>
|
||||
* Note how overlapping appointments are displayed in the provided image
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @version 1.0 6/07/09
|
||||
* @since 1.0
|
||||
*/
|
||||
public class DayViewLayoutStrategy {
|
||||
|
||||
private static final int MINUTES_PER_HOUR = 60;
|
||||
private static final int HOURS_PER_DAY = 24;
|
||||
private final HasSettings settings;
|
||||
|
||||
public DayViewLayoutStrategy(final HasSettings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public List<AppointmentAdapter> doLayout(List<Appointment> appointments, int dayIndex, int dayCount) {
|
||||
|
||||
int intervalsPerHour = settings.getSettings().getIntervalsPerHour(); //30 minute intervals
|
||||
float intervalSize = settings.getSettings().getPixelsPerInterval(); //25 pixels per interval
|
||||
|
||||
/*
|
||||
* Note: it is important that all appointments are sorted by Start date
|
||||
* (asc) and Duration (desc) for this algorithm to work. If that is not
|
||||
* the case, it won't work, at all!! Maybe this is a problem that needs
|
||||
* to be addressed
|
||||
*/
|
||||
|
||||
// set to 30 minutes. this means there will be 48 cells. 60min / 30min
|
||||
// interval * 24
|
||||
//int minutesPerInterval = 30;
|
||||
// interval size, set to 100px
|
||||
//float sizeOfInterval = 25f;
|
||||
|
||||
// a calendar can view multiple days at a time. sets number of visible
|
||||
// days
|
||||
// TODO: use this later, not currently implemented
|
||||
// float numberOfDays = dates.size();
|
||||
|
||||
int minutesPerInterval = MINUTES_PER_HOUR / intervalsPerHour;
|
||||
|
||||
// get number of cells (time blocks)
|
||||
int numberOfTimeBlocks = MINUTES_PER_HOUR / minutesPerInterval * HOURS_PER_DAY;
|
||||
TimeBlock[] timeBlocks = new TimeBlock[numberOfTimeBlocks];
|
||||
|
||||
for (int i = 0; i < numberOfTimeBlocks; i++) {
|
||||
TimeBlock t = new TimeBlock();
|
||||
t.setStart(i * minutesPerInterval);
|
||||
t.setEnd(t.getStart() + minutesPerInterval);
|
||||
t.setOrder(i);
|
||||
t.setTop((float) i * intervalSize);
|
||||
t.setBottom(t.getTop() + intervalSize);
|
||||
timeBlocks[i] = t;
|
||||
}
|
||||
|
||||
// each appointment will get "wrapped" in an appoinetment cell object,
|
||||
// so that we can assign it a location in the grid, row and
|
||||
// column span, etc.
|
||||
ArrayList<AppointmentAdapter> appointmentCells = new ArrayList<AppointmentAdapter>();
|
||||
// Map<TimeBlock,TimeBlock> blockGroup = new
|
||||
// HashMap<TimeBlock,TimeBlock>();
|
||||
int groupMaxColumn = 0; // track total columns here! this will reset
|
||||
// when a group completes
|
||||
int groupStartIndex = -1;
|
||||
int groupEndIndex = -2;
|
||||
|
||||
// Question: how to distinguish start / finish of a new group?
|
||||
// Answer: when endCell of previous appointments < startCell of new
|
||||
// appointment
|
||||
|
||||
// for each appointments, we need to see if it intersects with each time
|
||||
// block
|
||||
for (Appointment appointment : appointments) {
|
||||
|
||||
TimeBlock startBlock = null;
|
||||
TimeBlock endBlock = null;
|
||||
|
||||
// if(blockGroupEndCell)
|
||||
|
||||
// wrap appointment with AppointmentInterface Cell and add to list
|
||||
AppointmentAdapter apptCell = new AppointmentAdapter(appointment);
|
||||
appointmentCells.add(apptCell);
|
||||
|
||||
// get the first time block in which the appointment should appear
|
||||
// TODO: since appointments are sorted, we should never need to
|
||||
// re-evaluate a time block that had zero matches...
|
||||
// store the index of the currently evaluated time block, if no
|
||||
// match, increment
|
||||
// that will prevent the same block from ever being re-evaluated
|
||||
// after no match found
|
||||
for (TimeBlock block : timeBlocks) {
|
||||
// does the appointment intersect w/ the block???
|
||||
if (block.intersectsWith(apptCell)) {
|
||||
|
||||
// we found one! set as start block and exit loop
|
||||
startBlock = block;
|
||||
// blockGroup.put(block, block);
|
||||
|
||||
if (groupEndIndex < startBlock.getOrder()) {
|
||||
|
||||
//System.out.println(" prior group max cols: "
|
||||
// + groupMaxColumn);
|
||||
|
||||
for (int i = groupStartIndex; i <= groupEndIndex; i++) {
|
||||
|
||||
TimeBlock tb = timeBlocks[i];
|
||||
tb.setTotalColumns(groupMaxColumn + 1);
|
||||
//System.out.println(" total col set for block: "
|
||||
// + i);
|
||||
}
|
||||
groupStartIndex = startBlock.getOrder();
|
||||
//System.out.println("new group at: " + groupStartIndex);
|
||||
groupMaxColumn = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
} else {
|
||||
// here is where I would increment, as per above to-do
|
||||
}
|
||||
}
|
||||
|
||||
// add the appointment to the start block
|
||||
startBlock.getAppointments().add(apptCell);
|
||||
// add block to appointment
|
||||
apptCell.getIntersectingBlocks().add(startBlock);
|
||||
|
||||
// set the appointments column, if it has not already been set
|
||||
// if it has been set, we need to get it for reference later on in
|
||||
// this method
|
||||
int column = startBlock.getFirstAvailableColumn();
|
||||
apptCell.setColumnStart(column);
|
||||
apptCell.setColumnSpan(1); // hard-code to 1, for now
|
||||
|
||||
// we track the max column for a time block
|
||||
// if a column get's added make sure we increment
|
||||
// if (startBlock.getTotalColumns() <= column) {
|
||||
// startBlock.setTotalColumns(column+1);
|
||||
// }
|
||||
|
||||
// add column to block's list of occupied columns, so that the
|
||||
// column cannot be given to another appointment
|
||||
startBlock.getOccupiedColumns().put(column, column);
|
||||
|
||||
// sets the start cell of the appt to the current block
|
||||
// we can do this since the blocks are ordered ascending
|
||||
apptCell.setCellStart(startBlock.getOrder());
|
||||
|
||||
// go through all subsequent blocks...
|
||||
// find intersections
|
||||
for (int i = startBlock.getOrder() + 1; i < timeBlocks.length; i++) {
|
||||
|
||||
// get the nextTimeBlock
|
||||
TimeBlock nextBlock = timeBlocks[i];
|
||||
|
||||
// exit look if end date > block start, since no subsequent
|
||||
// blocks will ever intersect
|
||||
// if (apptCell.getAppointmentEnd() > nextBlock.getStart()) {
|
||||
// break; //does appt intersect with this block?
|
||||
// }
|
||||
if (nextBlock.intersectsWith(apptCell)) {
|
||||
|
||||
// yes! add appointment to the block
|
||||
// register start column
|
||||
nextBlock.getAppointments().add(apptCell);
|
||||
nextBlock.getOccupiedColumns().put(column, column);
|
||||
endBlock = nextBlock; // this may change if intersects with
|
||||
// next block
|
||||
|
||||
// add block to appointments list of intersecting blocks
|
||||
apptCell.getIntersectingBlocks().add(nextBlock);
|
||||
|
||||
// we track the max column for a time block
|
||||
// if a column get's added make sure we increment
|
||||
// if (nextBlock.getTotalColumns() <= column) {
|
||||
// nextBlock.setTotalColumns(column+1);
|
||||
// }
|
||||
|
||||
// blockGroup.put(nextBlock, nextBlock);
|
||||
}
|
||||
}
|
||||
|
||||
// if end block was never set, use the start block
|
||||
endBlock = (endBlock == null) ? startBlock : endBlock;
|
||||
// maybe here is the "end" of a group, where we then evaluate max
|
||||
// column
|
||||
|
||||
if (column > groupMaxColumn) {
|
||||
groupMaxColumn = column;
|
||||
// System.out.println(" max col: " + groupMaxColumn);
|
||||
}
|
||||
|
||||
if (groupEndIndex < endBlock.getOrder()) {
|
||||
groupEndIndex = endBlock.getOrder();
|
||||
//System.out.println(" end index (re)set: " + groupEndIndex);
|
||||
}
|
||||
// for(int i = groupStartIndex; i<=groupEndIndex; i++) {
|
||||
// timeBlocks[i].setTotalColumns(groupMaxColumn);
|
||||
// }
|
||||
// groupMaxColumn=1;
|
||||
// }
|
||||
|
||||
// for(TimeBlock timeBlock : blockGroup.values()) {
|
||||
//
|
||||
// }
|
||||
|
||||
// blockGroup = new HashMap<TimeBlock,TimeBlock>();
|
||||
|
||||
// set the appointments cell span (top to bottom)
|
||||
apptCell.setCellSpan(endBlock.getOrder() - startBlock.getOrder() + 1);
|
||||
|
||||
}
|
||||
for (int i = groupStartIndex; i <= groupEndIndex; i++) {
|
||||
|
||||
TimeBlock tb = timeBlocks[i];
|
||||
tb.setTotalColumns(groupMaxColumn + 1);
|
||||
//System.out.println(" total col set for block: " + i);
|
||||
}
|
||||
// we need to know the MAX number of cells for each time block.
|
||||
// so unfortunately we have to go back through the list to find this out
|
||||
/*
|
||||
* for(AppointmentCell apptCell : appointmentCells) {
|
||||
*
|
||||
* for (TimeBlock block : apptCell.getIntersectingBlocks()) {
|
||||
*
|
||||
* int maxCol = 0;
|
||||
*
|
||||
* //find the max cell for (AppointmentCell apptCell :
|
||||
* block.getAppointments()) { int col = apptCell.getColumnStart(); if
|
||||
* (col > maxCol) { maxCol = col; } }
|
||||
*
|
||||
* block.setTotalColumns(maxCol+1); } }
|
||||
*/
|
||||
|
||||
|
||||
//last step is to calculate the adjustment reuired for 'multi-day' / multi-column
|
||||
float widthAdj = 1f / dayCount;
|
||||
|
||||
float paddingLeft = .5f;
|
||||
float paddingRight = .5f;
|
||||
float paddingBottom = 2;
|
||||
|
||||
// now that everything has been assigned a cell, column and spans
|
||||
// we can calculate layout
|
||||
// Note: this can only be done after every single appointment has
|
||||
// been assigned a position in the grid
|
||||
for (AppointmentAdapter apptCell : appointmentCells) {
|
||||
|
||||
float width = 1f / (float) apptCell.getIntersectingBlocks().get(0).getTotalColumns() * 100;
|
||||
float left = (float) apptCell.getColumnStart() / (float) apptCell.getIntersectingBlocks().get(0).getTotalColumns() * 100;
|
||||
|
||||
//AppointmentInterface appt = apptCell.getAppointment();
|
||||
apptCell.setTop((float) apptCell.getCellStart() * intervalSize); // ok!
|
||||
apptCell.setLeft((widthAdj * 100 * dayIndex) + (left * widthAdj) + paddingLeft); // ok
|
||||
apptCell.setWidth(width * widthAdj - paddingLeft - paddingRight); // ok!
|
||||
apptCell.setHeight((float) apptCell.getIntersectingBlocks().size() * ((float) intervalSize) - paddingBottom); // ok!
|
||||
|
||||
float apptStart = apptCell.getAppointmentStart();
|
||||
float apptEnd = apptCell.getAppointmentEnd();
|
||||
float blockStart = timeBlocks[apptCell.getCellStart()].getStart();
|
||||
float blockEnd = timeBlocks[apptCell.getCellStart() + apptCell.getCellSpan() - 1].getEnd();
|
||||
float blockDuration = blockEnd - blockStart;
|
||||
float apptDuration = apptEnd - apptStart;
|
||||
float timeFillHeight = apptDuration / blockDuration * 100f;
|
||||
float timeFillStart = (apptStart - blockStart) / blockDuration * 100f;
|
||||
// System.out.println("apptStart: "+apptStart);
|
||||
// System.out.println("apptEnd: "+apptEnd);
|
||||
// System.out.println("blockStart: "+blockStart);
|
||||
// System.out.println("blockEnd: "+blockEnd);
|
||||
// System.out.println("timeFillHeight: "+timeFillHeight);
|
||||
//System.out.println("timeFillStart: "+timeFillStart);
|
||||
//System.out.println("------------");
|
||||
apptCell.setCellPercentFill(timeFillHeight);
|
||||
apptCell.setCellPercentStart(timeFillStart);
|
||||
//appt.formatTimeline(apptCell.getCellPercentStart(), apptCell.getCellPercentFill());
|
||||
}
|
||||
|
||||
return appointmentCells;
|
||||
}
|
||||
|
||||
public int doMultiDayLayout(List<Appointment> appointments, List<AppointmentAdapter> adapters, Date start, int days) {
|
||||
|
||||
//create array to hold all appointments for a particular day
|
||||
//HashMap<Date, ArrayList<AppointmentAdapter>> appointmentDayMap
|
||||
// = new HashMap<Date, ArrayList<AppointmentAdapter>>();
|
||||
|
||||
//for a particular day need to track all used rows
|
||||
HashMap<Integer, HashMap<Integer, Integer>> daySlotMap = new HashMap<Integer, HashMap<Integer, Integer>>();
|
||||
|
||||
int minHeight = 30;
|
||||
int maxRow = 0;
|
||||
|
||||
|
||||
//convert appointment to adapter
|
||||
for (Appointment appointment : appointments) {
|
||||
adapters.add(new AppointmentAdapter(appointment));
|
||||
}
|
||||
|
||||
//create array of dates
|
||||
ArrayList<Date> dateList = new ArrayList<Date>();
|
||||
Date tempStartDate = (Date)start.clone();
|
||||
|
||||
// tempStartDate.setHours(0);
|
||||
// tempStartDate.setMinutes(0);
|
||||
// tempStartDate.setSeconds(0);
|
||||
for (int i = 0; i < days; i++) {
|
||||
Date d = (Date) tempStartDate.clone();
|
||||
DateUtils.resetTime(d);
|
||||
//appointmentDayMap.put(d, new ArrayList<AppointmentAdapter>());
|
||||
daySlotMap.put(i, new HashMap<Integer, Integer>());
|
||||
dateList.add(d);
|
||||
DateUtils.moveOneDayForward(tempStartDate);
|
||||
}
|
||||
|
||||
|
||||
//add appointments to each day
|
||||
for (AppointmentAdapter adapter : adapters) {
|
||||
|
||||
int columnSpan = 0; //number of columns spanned
|
||||
boolean isStart = true; //indicates if current column is appointment start column
|
||||
|
||||
//set column & span
|
||||
for (int i = 0; i < dateList.size(); i++) {
|
||||
Date date = dateList.get(i);
|
||||
boolean isWithinRange =
|
||||
AppointmentUtil.rangeContains(
|
||||
adapter.getAppointment(), date);
|
||||
|
||||
//System.out.println(" isWithinRange == " + isWithinRange + " for start: " + adapter.getAppointment().getStart() + " end: " + adapter.getAppointment().getEnd() + " date: "+date);
|
||||
|
||||
//while we are at it, we can set the adapters start column
|
||||
// and colun span
|
||||
if (isWithinRange) {
|
||||
//appointmentDayMap.get(date).add(adapter);
|
||||
|
||||
if (isStart) {
|
||||
adapter.setColumnStart(i);
|
||||
isStart = false;
|
||||
}
|
||||
|
||||
adapter.setColumnSpan(columnSpan);
|
||||
columnSpan++;
|
||||
}
|
||||
}
|
||||
|
||||
//now we set the row, which cannot be more than total # of appointments
|
||||
for (int x = 0; x < adapters.size(); x++) {
|
||||
|
||||
boolean isRowOccupied = false;
|
||||
for (int y = adapter.getColumnStart(); y <= adapter.getColumnStart() + adapter.getColumnSpan(); y++) {
|
||||
try{
|
||||
HashMap<Integer, Integer> rowMap = daySlotMap.get(y);
|
||||
if (rowMap.containsKey(x)) {
|
||||
isRowOccupied = true;
|
||||
//System.out.println(" row [" + x+"] is occupied for day [" + y+"]");
|
||||
} else {
|
||||
//isRowOccupied = false;
|
||||
break; //break out of loop, nothing found in row slot
|
||||
}
|
||||
}catch(Exception ex) {
|
||||
//System.out.println("Exception: y=" + y + " x=" + x + " adapters.size=" + adapters.size() + " start="+adapter.getAppointment().getStart() + " end="+adapter.getAppointment().getEnd().toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (!isRowOccupied) {
|
||||
//add row to maps
|
||||
for (int y = adapter.getColumnStart(); y <= adapter.getColumnStart() + adapter.getColumnSpan(); y++) {
|
||||
HashMap<Integer, Integer> rowMap = daySlotMap.get(y);
|
||||
rowMap.put(x, x);
|
||||
if (x > maxRow) {
|
||||
maxRow = x;
|
||||
}
|
||||
//System.out.println(" > added "+ x + " to row list for column " + y);
|
||||
}
|
||||
//set the row (also named cell)
|
||||
adapter.setCellStart(x);
|
||||
//break loop
|
||||
|
||||
|
||||
//now we set the appointment's location
|
||||
//Appointment appt = adapter.getAppointment();
|
||||
float top = adapter.getCellStart() * 25f + 5f;
|
||||
float width = ((float) adapter.getColumnSpan() + 1f) / days * 100f - 1f; //10f=padding
|
||||
float left = ((float) adapter.getColumnStart()) / days * 100f + .5f; //10f=padding
|
||||
//float left = (float) adapter.getColumnStart() / (float) apptCell.getIntersectingBlocks().get(0).getTotalColumns() * 100;
|
||||
adapter.setWidth(width);
|
||||
adapter.setLeft(left);
|
||||
adapter.setTop(top);
|
||||
adapter.setHeight(20);
|
||||
//System.out.println("set appointment [" + appt.getTitle() + "] layout left: " + left + " top: " + top + " width: " + width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("multi-day layout -- title: \"" + adapter.getAppointment().getTitle() + "\" | col start: " + adapter.getColumnStart() + " | colspan: " + adapter.getColumnSpan() + " | row: " + adapter.getCellStart() + " | start date: " + adapter.getAppointment().getStart() + " | end date: " + adapter.getAppointment().getEnd());
|
||||
|
||||
|
||||
}
|
||||
|
||||
int height = (maxRow + 1) * 25 + 5;
|
||||
return Math.max(height, minHeight);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.WindowUtils;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
|
||||
/**
|
||||
* A widget to render multi-day appointments in a day view.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class DayViewMultiDayBody extends Composite {
|
||||
|
||||
private FlexTable header = new FlexTable();
|
||||
protected AbsolutePanel grid = new AbsolutePanel();
|
||||
private AbsolutePanel splitter = new AbsolutePanel();
|
||||
private static final String TIMELINE_EMPTY_CELL_STYLE = "leftEmptyCell";
|
||||
private static final String SCROLLBAR_EMPTY_CELL_STYLE = "rightEmptyCell";
|
||||
private static final String DAY_CONTAINER_CELL_STYLE = "centerDayContainerCell";
|
||||
private static final String SPLITTER_STYLE = "splitter";
|
||||
protected SimplePanel gridOverlay = new SimplePanel();
|
||||
|
||||
public DayViewMultiDayBody(HasSettings settings) {
|
||||
|
||||
initWidget(header);
|
||||
|
||||
this.header.setStyleName("multiDayBody");
|
||||
this.setWidth("100%");
|
||||
|
||||
/* insert two rows ... first row holds multi-day appointments,
|
||||
* second row is just a splitter */
|
||||
header.insertRow(0);
|
||||
header.insertRow(0);
|
||||
//insert 3 cells
|
||||
//1st cell is empty to align with the timeline
|
||||
//2nd cell holds appointments
|
||||
//3rd cell is empty, aligns with scrollbar
|
||||
header.insertCell(0, 0);
|
||||
header.insertCell(0, 0);
|
||||
header.insertCell(0, 0);
|
||||
|
||||
//add panel to hold appointments
|
||||
header.setWidget(0, 1, grid);
|
||||
|
||||
//set cell styles
|
||||
header.getCellFormatter().setStyleName(0, 0, TIMELINE_EMPTY_CELL_STYLE);
|
||||
header.getCellFormatter().setStyleName(0, 1, DAY_CONTAINER_CELL_STYLE);
|
||||
header.getCellFormatter().setStyleName(0, 2, SCROLLBAR_EMPTY_CELL_STYLE);
|
||||
header.getCellFormatter().setWidth(0, 2,
|
||||
WindowUtils.getScrollBarWidth(true) + "px");
|
||||
|
||||
//default grid to 50px height
|
||||
grid.setHeight("30px");
|
||||
|
||||
header.getFlexCellFormatter().setColSpan(1, 0, 3);
|
||||
header.setCellPadding(0);
|
||||
header.setBorderWidth(0);
|
||||
header.setCellSpacing(0);
|
||||
|
||||
splitter.setStylePrimaryName(SPLITTER_STYLE);
|
||||
header.setWidget(1, 0, splitter);
|
||||
}
|
||||
|
||||
public void setDays(Date date, int days) {
|
||||
|
||||
grid.clear();
|
||||
float dayWidth = 100f / days;
|
||||
float dayLeft;
|
||||
|
||||
for (int day = 0; day < days; day++) {
|
||||
dayLeft = dayWidth * day;
|
||||
SimplePanel dayPanel = new SimplePanel();
|
||||
dayPanel.setStyleName("day-separator");
|
||||
grid.add(dayPanel);
|
||||
DOM.setStyleAttribute(dayPanel.getElement(), "left", dayLeft + "%");
|
||||
}
|
||||
|
||||
gridOverlay.setHeight("100%");
|
||||
gridOverlay.setWidth("100%");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "position", "absolute");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "left", "0px");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "top", "0px");
|
||||
grid.add(gridOverlay);
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.ThemeAppointmentStyle;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
|
||||
public abstract class DayViewStyleManager {
|
||||
|
||||
protected static final String APPOINTMENT_STYLE = "dv-appointment";
|
||||
|
||||
protected static final String APPOINTMENT_STYLE_SELECTED = "-selected";
|
||||
|
||||
protected static final String APPOINTMENT_STYLE_MULTIDAY = "-multiday";
|
||||
|
||||
protected static final String BACKGROUND_COLOR_STYLE_ATTRIBUTE = "backgroundColor";
|
||||
|
||||
protected static final String BACKGROUND_IMAGE_STYLE_ATTRIBUTE = "backgroundImage";
|
||||
|
||||
protected static final String BORDER_COLOR_STYLE_ATTRIBUTE = "borderColor";
|
||||
|
||||
protected static final String COLOR_STYLE_ATTRIBUTE = "color";
|
||||
|
||||
public void applyStyle(AppointmentWidget widget, boolean selected) {
|
||||
doApplyStyleInternal(widget, selected);
|
||||
}
|
||||
|
||||
protected abstract ThemeAppointmentStyle getViewAppointmentStyleForTheme(Appointment appointment);
|
||||
|
||||
protected abstract ThemeAppointmentStyle getDefaultViewAppointmentStyleForTheme();
|
||||
|
||||
private void doApplyStyleInternal(AppointmentWidget widget, boolean selected) {
|
||||
|
||||
// Extract the Appointment for later reference
|
||||
Appointment appointment = widget.getAppointment();
|
||||
// Extract the DOM Element for later reference
|
||||
Element elem = widget.getElement();
|
||||
Element bodyElem = widget.getBody().getElement();
|
||||
Element headerElem = widget.getHeader().getElement();
|
||||
// Is MultiDay?
|
||||
boolean multiDay = appointment.isMultiDay() || appointment.isAllDay();
|
||||
|
||||
//Lookup the style from the map
|
||||
ThemeAppointmentStyle style = getViewAppointmentStyleForTheme(appointment);
|
||||
|
||||
//Determine Style Name
|
||||
String styleName = APPOINTMENT_STYLE;
|
||||
if(multiDay) styleName+=APPOINTMENT_STYLE_MULTIDAY;
|
||||
if(selected) styleName+=APPOINTMENT_STYLE_SELECTED;
|
||||
widget.setStylePrimaryName(styleName);
|
||||
|
||||
//If no style is found, apply the default blue style
|
||||
//TODO: need to check for a custom style
|
||||
if(style==null)
|
||||
style = getDefaultViewAppointmentStyleForTheme();
|
||||
|
||||
if (multiDay)
|
||||
DOM.setStyleAttribute(elem, BACKGROUND_COLOR_STYLE_ATTRIBUTE, style.getBackgroundHeader());
|
||||
else
|
||||
DOM.setStyleAttribute(elem, BACKGROUND_COLOR_STYLE_ATTRIBUTE, style.getBackground());
|
||||
|
||||
DOM.setStyleAttribute(elem, BORDER_COLOR_STYLE_ATTRIBUTE, style.getBackgroundHeader());
|
||||
|
||||
DOM.setStyleAttribute(bodyElem, COLOR_STYLE_ATTRIBUTE, style.getSelectedBorder());
|
||||
|
||||
DOM.setStyleAttribute(headerElem, COLOR_STYLE_ATTRIBUTE, style.getHeaderText());
|
||||
|
||||
DOM.setStyleAttribute(headerElem, BACKGROUND_COLOR_STYLE_ATTRIBUTE, style.getBackgroundHeader());
|
||||
|
||||
if (multiDay)
|
||||
return;
|
||||
|
||||
if (selected && style.getSelectedBackgroundImage() != null) {
|
||||
DOM.setStyleAttribute(elem, BACKGROUND_IMAGE_STYLE_ATTRIBUTE, "url("+ style.getSelectedBackgroundImage() + ")");
|
||||
} else {
|
||||
DOM.setStyleAttribute(elem, BACKGROUND_IMAGE_STYLE_ATTRIBUTE, "none");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarFormat;
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.FormattingUtil;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
|
||||
/**
|
||||
* A sequential display of the hours in a day. Each
|
||||
* hour label should visually line up to a cell in the DayGrid.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class DayViewTimeline extends Composite {
|
||||
|
||||
private AbsolutePanel timelinePanel = new AbsolutePanel();
|
||||
private HasSettings settings = null;
|
||||
private static final String TIME_LABEL_STYLE = "hour-label";
|
||||
|
||||
public DayViewTimeline(HasSettings settings) {
|
||||
initWidget(timelinePanel);
|
||||
timelinePanel.setStylePrimaryName("time-strip");
|
||||
this.settings = settings;
|
||||
prepare();
|
||||
}
|
||||
|
||||
public final void prepare() {
|
||||
timelinePanel.clear();
|
||||
float labelHeight = settings.getSettings().getIntervalsPerHour()
|
||||
* settings.getSettings().getPixelsPerInterval();
|
||||
|
||||
int i = 0;
|
||||
if (settings.getSettings().isOffsetHourLabels()) {
|
||||
i = 1;
|
||||
SimplePanel sp = new SimplePanel();
|
||||
sp.setHeight((labelHeight / 2) + "px");
|
||||
timelinePanel.add(sp);
|
||||
}
|
||||
|
||||
int dayStartsAt = settings.getSettings().getDayStartsAt();
|
||||
|
||||
while (i < CalendarFormat.HOURS_IN_DAY) {
|
||||
int index = i + dayStartsAt;
|
||||
if (index >= CalendarFormat.HOURS_IN_DAY) {
|
||||
index = index - CalendarFormat.HOURS_IN_DAY;
|
||||
}
|
||||
String hour = CalendarFormat.INSTANCE.getHourLabels()[index];
|
||||
index++;
|
||||
i++;
|
||||
|
||||
//block
|
||||
SimplePanel hourWrapper = new SimplePanel();
|
||||
hourWrapper.setStylePrimaryName(TIME_LABEL_STYLE);
|
||||
hourWrapper.setHeight((labelHeight + FormattingUtil.getBorderOffset()) + "px");
|
||||
|
||||
FlowPanel flowPanel = new FlowPanel();
|
||||
flowPanel.setStyleName("hour-layout");
|
||||
|
||||
String amPm = " ";
|
||||
|
||||
if (index < 13)
|
||||
amPm += CalendarFormat.INSTANCE.getAm();
|
||||
else if (index > 13)
|
||||
amPm += CalendarFormat.INSTANCE.getPm();
|
||||
else {
|
||||
if (CalendarFormat.INSTANCE.isUseNoonLabel()) {
|
||||
hour = CalendarFormat.INSTANCE.getNoon();
|
||||
amPm = "";
|
||||
} else {
|
||||
amPm += CalendarFormat.INSTANCE.getPm();
|
||||
}
|
||||
}
|
||||
|
||||
Label hourLabel = new Label(hour);
|
||||
hourLabel.setStylePrimaryName("hour-text");
|
||||
flowPanel.add(hourLabel);
|
||||
|
||||
Label amPmLabel = new Label(amPm);
|
||||
amPmLabel.setStylePrimaryName("ampm-text");
|
||||
flowPanel.add(amPmLabel);
|
||||
|
||||
hourWrapper.add(flowPanel);
|
||||
|
||||
timelinePanel.add(hourWrapper);
|
||||
}
|
||||
}
|
||||
}
|
148
src/com/bradrydzewski/gwt/calendar/client/dayview/TimeBlock.java
Normal file
148
src/com/bradrydzewski/gwt/calendar/client/dayview/TimeBlock.java
Normal file
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.dayview;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a block of time that contains one or many Appointments. An example
|
||||
* of a timeblock could be 10am - 10:30 am, where a block of time is 30 minutes.
|
||||
* <p> A block of time can contain or be interested by one or many appointments.
|
||||
* Using the above example, a time block from 10am - 10:30 am could contain the
|
||||
* following appointments:
|
||||
* <ul>
|
||||
* <li>10:00 - 10:30, where start / end are same as time block</li>
|
||||
* <li>9:00 - 10:30, where the appointment starts before the time block
|
||||
* starts but ends at same time as time block</li>
|
||||
* <li>9:00 - 10:20, where appointment start before
|
||||
* and ends after start of time block</li>
|
||||
* <li>9:00 - 11:00, where appointment starts before and ends after the time
|
||||
* block does</li>
|
||||
* <li>10:05 - 10:25, where appointment starts after but ends before the
|
||||
* time block</li> </ul></p>
|
||||
* Above
|
||||
* are example use cases of a time block and how it relates to an appointment.
|
||||
* Note that an appointment can intersect with one ore many time blocks. This
|
||||
* class holds a number of parameters allowing a time block to manage its
|
||||
* appointments and determine where the appointments should be arranged within
|
||||
* itself.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class TimeBlock {
|
||||
private List<AppointmentAdapter> appointments = new ArrayList<AppointmentAdapter>();
|
||||
private Map<Integer, Integer> occupiedColumns = new HashMap<Integer, Integer>();
|
||||
private int totalColumns = 1;
|
||||
private int order;
|
||||
private String name;
|
||||
private int start;
|
||||
private int end;
|
||||
private float top;
|
||||
private float bottom;
|
||||
|
||||
public List<AppointmentAdapter> getAppointments() {
|
||||
return appointments;
|
||||
}
|
||||
|
||||
public Map<Integer, Integer> getOccupiedColumns() {
|
||||
return occupiedColumns;
|
||||
}
|
||||
|
||||
public int getFirstAvailableColumn() {
|
||||
int col = 0;
|
||||
while (true) {
|
||||
if (occupiedColumns.containsKey(col))
|
||||
col++;
|
||||
else return col;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTotalColumns() {
|
||||
return totalColumns;
|
||||
}
|
||||
|
||||
public void setTotalColumns(int totalColumns) {
|
||||
this.totalColumns = totalColumns;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(int end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public float getBottom() {
|
||||
return bottom;
|
||||
}
|
||||
|
||||
public void setBottom(float bottom) {
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public float getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public void setTop(float top) {
|
||||
this.top = top;
|
||||
}
|
||||
|
||||
public boolean intersectsWith(int apptStart, int apptEnd) {
|
||||
//scenario 1: start date of appt between start and end of block
|
||||
if (apptStart >= this.getStart() && apptStart < this.getEnd())
|
||||
return true;
|
||||
|
||||
//scenario 2: end date of appt > block start date &
|
||||
// start date of appt before block start date
|
||||
return apptEnd > this.getStart() && apptStart < this.getStart();
|
||||
}
|
||||
|
||||
public boolean intersectsWith(AppointmentAdapter appt) {
|
||||
return intersectsWith(appt.getAppointmentStart(),
|
||||
appt.getAppointmentEnd());
|
||||
}
|
||||
}
|
107
src/com/bradrydzewski/gwt/calendar/client/event/CreateEvent.java
Normal file
107
src/com/bradrydzewski/gwt/calendar/client/event/CreateEvent.java
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
|
||||
/**
|
||||
* TODO: Complete JavaDoc comments.
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class CreateEvent<T> extends GwtEvent<CreateHandler<T>> {
|
||||
|
||||
/**
|
||||
* Handler type.
|
||||
*/
|
||||
private static Type<CreateHandler<?>> TYPE;
|
||||
|
||||
private boolean cancelled = false;
|
||||
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fires a open event on all registered handlers in the handler manager.If no
|
||||
* such handlers exist, this method will do nothing.
|
||||
*
|
||||
* @param <T> the target type
|
||||
* @param source the source of the handlers
|
||||
* @param target the target
|
||||
*/
|
||||
public static <T> boolean fire(HasUpdateHandlers<T> source, T target) {
|
||||
if (TYPE != null) {
|
||||
CreateEvent<T> event = new CreateEvent<T>(target);
|
||||
source.fireEvent(event);
|
||||
return !event.isCancelled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type associated with this event.
|
||||
*
|
||||
* @return returns the handler type
|
||||
*/
|
||||
public static Type<CreateHandler<?>> getType() {
|
||||
if (TYPE == null) {
|
||||
TYPE = new Type<CreateHandler<?>>();
|
||||
}
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
private final T target;
|
||||
|
||||
/**
|
||||
* Creates a new delete event.
|
||||
*
|
||||
* @param target the ui object being opened
|
||||
*/
|
||||
protected CreateEvent(T target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Type<CreateHandler<T>> getAssociatedType() {
|
||||
return (Type) TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target.
|
||||
*
|
||||
* @return the target
|
||||
*/
|
||||
public T getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
// Because of type erasure, our static type is
|
||||
// wild carded, yet the "real" type should use our I param.
|
||||
|
||||
@Override
|
||||
protected void dispatch(CreateHandler<T> handler) {
|
||||
handler.onCreate(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.EventHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Handler interface for {@link DeleteEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface CreateHandler<T> extends EventHandler {
|
||||
|
||||
/**
|
||||
* Called when {@link DeleteEvent} is fired.
|
||||
*
|
||||
* @param event the {@link DeleteEvent} that was fired
|
||||
*/
|
||||
void onCreate(CreateEvent<T> event);
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
|
||||
/**
|
||||
* TODO: Complete JavaDoc comments.
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class DateRequestEvent<T> extends GwtEvent<DateRequestHandler<T>> {
|
||||
|
||||
/**
|
||||
* Handler type.
|
||||
*/
|
||||
private static Type<DateRequestHandler<?>> TYPE;
|
||||
|
||||
/**
|
||||
* Fires a open event on all registered handlers in the handler manager.If no
|
||||
* such handlers exist, this method will do nothing.
|
||||
*
|
||||
* @param <T> the target type
|
||||
* @param source the source of the handlers
|
||||
* @param target the target
|
||||
*/
|
||||
public static <T> void fire(HasDateRequestHandlers<T> source, T target) {
|
||||
fire(source, target, null);
|
||||
}
|
||||
|
||||
public static <T> void fire(HasDateRequestHandlers<T> source, T target, Object widget) {
|
||||
if (TYPE != null) {
|
||||
DateRequestEvent<T> event = new DateRequestEvent<T>(target, widget);
|
||||
source.fireEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type associated with this event.
|
||||
*
|
||||
* @return returns the handler type
|
||||
*/
|
||||
public static Type<DateRequestHandler<?>> getType() {
|
||||
if (TYPE == null) {
|
||||
TYPE = new Type<DateRequestHandler<?>>();
|
||||
}
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
private final T target;
|
||||
private final Object clicked;
|
||||
|
||||
/**
|
||||
* Creates a new delete event.
|
||||
*
|
||||
* @param target the ui object being opened
|
||||
*/
|
||||
protected DateRequestEvent(T target, Object clicked) {
|
||||
this.target = target;
|
||||
this.clicked = clicked;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Type<DateRequestHandler<T>> getAssociatedType() {
|
||||
return (Type) TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target.
|
||||
*
|
||||
* @return the target
|
||||
*/
|
||||
public T getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public Object getClicked() {
|
||||
return clicked;
|
||||
}
|
||||
|
||||
// Because of type erasure, our static type is
|
||||
// wild carded, yet the "real" type should use our I param.
|
||||
|
||||
@Override
|
||||
protected void dispatch(DateRequestHandler<T> handler) {
|
||||
handler.onDateRequested(this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.EventHandler;
|
||||
|
||||
public interface DateRequestHandler<T> extends EventHandler {
|
||||
|
||||
/**
|
||||
* Called when {@link DeleteEvent} is fired.
|
||||
*
|
||||
* @param event the {@link DeleteEvent} that was fired
|
||||
*/
|
||||
void onDateRequested(DateRequestEvent<T> event);
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
|
||||
/**
|
||||
* Represents a selection event.
|
||||
*
|
||||
* @param <T>
|
||||
* the type being selected
|
||||
*/
|
||||
public class DaySelectionEvent<T> extends GwtEvent<DaySelectionHandler<T>> {
|
||||
|
||||
/**
|
||||
* Handler type.
|
||||
*/
|
||||
private static Type<DaySelectionHandler<?>> TYPE;
|
||||
|
||||
/**
|
||||
* Fires a selection event on all registered handlers in the handler
|
||||
* manager.If no such handlers exist, this method will do nothing.
|
||||
*
|
||||
* @param <T>
|
||||
* the selected item type
|
||||
* @param source
|
||||
* the source of the handlers
|
||||
* @param selectedItem
|
||||
* the selected item
|
||||
*/
|
||||
public static <T> void fire(HasDaySelectionHandlers<T> source, T selectedItem) {
|
||||
if (TYPE != null) {
|
||||
DaySelectionEvent<T> event = new DaySelectionEvent<T>(
|
||||
selectedItem);
|
||||
source.fireEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type associated with this event.
|
||||
*
|
||||
* @return returns the handler type
|
||||
*/
|
||||
public static Type<DaySelectionHandler<?>> getType() {
|
||||
if (TYPE == null) {
|
||||
TYPE = new Type<DaySelectionHandler<?>>();
|
||||
}
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
private final T selectedItem;
|
||||
|
||||
/**
|
||||
* Creates a new selection event.
|
||||
*
|
||||
* @param selectedItem
|
||||
* selected item
|
||||
*/
|
||||
protected DaySelectionEvent(T selectedItem) {
|
||||
this.selectedItem = selectedItem;
|
||||
}
|
||||
|
||||
// The instance knows its BeforeSelectionHandler is of type I, but the TYPE
|
||||
// field itself does not, so we have to do an unsafe cast here.
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Type<DaySelectionHandler<T>> getAssociatedType() {
|
||||
return (Type) TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selected item.
|
||||
*
|
||||
* @return the selected item
|
||||
*/
|
||||
public T getSelectedItem() {
|
||||
return selectedItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatch(DaySelectionHandler<T> handler) {
|
||||
handler.onSelection(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.EventHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Handler interface for {@link DaySelectionEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface DaySelectionHandler<T> extends EventHandler {
|
||||
|
||||
/**
|
||||
* Called when {@link DaySelectionEvent} is fired.
|
||||
*
|
||||
* @param event the {@link DaySelectionEvent} that was fired
|
||||
*/
|
||||
void onSelection(DaySelectionEvent<T> event);
|
||||
}
|
106
src/com/bradrydzewski/gwt/calendar/client/event/DeleteEvent.java
Normal file
106
src/com/bradrydzewski/gwt/calendar/client/event/DeleteEvent.java
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
|
||||
/**
|
||||
* TODO: Complete Javadoc comments.
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class DeleteEvent<T> extends GwtEvent<DeleteHandler<T>> {
|
||||
|
||||
/**
|
||||
* Handler type.
|
||||
*/
|
||||
private static Type<DeleteHandler<?>> TYPE;
|
||||
|
||||
private boolean cancelled = false;
|
||||
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fires a open event on all registered handlers in the handler manager.If no
|
||||
* such handlers exist, this method will do nothing.
|
||||
*
|
||||
* @param <T> the target type
|
||||
* @param source the source of the handlers
|
||||
* @param target the target
|
||||
*/
|
||||
public static <T> boolean fire(HasDeleteHandlers<T> source, T target) {
|
||||
if (TYPE != null) {
|
||||
DeleteEvent<T> event = new DeleteEvent<T>(target);
|
||||
source.fireEvent(event);
|
||||
return !event.isCancelled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type associated with this event.
|
||||
*
|
||||
* @return returns the handler type
|
||||
*/
|
||||
public static Type<DeleteHandler<?>> getType() {
|
||||
if (TYPE == null) {
|
||||
TYPE = new Type<DeleteHandler<?>>();
|
||||
}
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
private final T target;
|
||||
|
||||
/**
|
||||
* Creates a new delete event.
|
||||
*
|
||||
* @param target the ui object being opened
|
||||
*/
|
||||
protected DeleteEvent(T target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Type<DeleteHandler<T>> getAssociatedType() {
|
||||
return (Type) TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target.
|
||||
*
|
||||
* @return the target
|
||||
*/
|
||||
public T getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
// Because of type erasure, our static type is
|
||||
// wild carded, yet the "real" type should use our I param.
|
||||
|
||||
@Override
|
||||
protected void dispatch(DeleteHandler<T> handler) {
|
||||
handler.onDelete(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.EventHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Handler interface for {@link DeleteEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface DeleteHandler<T> extends EventHandler {
|
||||
|
||||
/**
|
||||
* Called when {@link DeleteEvent} is fired.
|
||||
*
|
||||
* @param event the {@link DeleteEvent} that was fired
|
||||
*/
|
||||
void onDelete(DeleteEvent<T> event);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.event.shared.HasHandlers;
|
||||
|
||||
/**
|
||||
* A widget that implements this interface is a public source of
|
||||
* {@link DateRequestEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface HasDateRequestHandlers<T> extends HasHandlers {
|
||||
/**
|
||||
* Adds a {@link DateRequestEvent} handler.
|
||||
*
|
||||
* @param handler the handler
|
||||
* @return the registration for the event
|
||||
*/
|
||||
HandlerRegistration addDateRequestHandler(DateRequestHandler<T> handler);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.event.shared.HasHandlers;
|
||||
|
||||
/**
|
||||
* A widget that implements this interface is a public source of
|
||||
* {@link WeekSelectionEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface HasDaySelectionHandlers<T> extends HasHandlers {
|
||||
/**
|
||||
* Adds a {@link WeekSelectionEvent} handler.
|
||||
*
|
||||
* @param handler the handler
|
||||
* @return the registration for the event
|
||||
*/
|
||||
HandlerRegistration addDaySelectionHandler(DaySelectionHandler<T> handler);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.event.shared.HasHandlers;
|
||||
|
||||
/**
|
||||
* A widget that implements this interface is a public source of
|
||||
* {@link DeleteEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface HasDeleteHandlers<T> extends HasHandlers {
|
||||
/**
|
||||
* Adds a {@link DeleteEvent} handler.
|
||||
*
|
||||
* @param handler the handler
|
||||
* @return the registration for the event
|
||||
*/
|
||||
HandlerRegistration addDeleteHandler(DeleteHandler<T> handler);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.event.shared.HasHandlers;
|
||||
|
||||
/**
|
||||
* A widget that implements this interface is a public source of
|
||||
* {@link MouseOverEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface HasMouseOverHandlers<T> extends HasHandlers {
|
||||
/**
|
||||
* Adds a {@link DeleteEvent} handler.
|
||||
*
|
||||
* @param handler the handler
|
||||
* @return the registration for the event
|
||||
*/
|
||||
HandlerRegistration addMouseOverHandler(MouseOverHandler<T> handler);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.event.shared.HasHandlers;
|
||||
|
||||
/**
|
||||
* A widget that implements this interface is a public source of
|
||||
* {@link DeleteEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface HasTimeBlockClickHandlers<T> extends HasHandlers {
|
||||
/**
|
||||
* Adds a {@link DeleteEvent} handler.
|
||||
*
|
||||
* @param handler the handler
|
||||
* @return the registration for the event
|
||||
*/
|
||||
HandlerRegistration addTimeBlockClickHandler(TimeBlockClickHandler<T> handler);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.event.shared.HasHandlers;
|
||||
|
||||
/**
|
||||
* A widget that implements this interface is a public source of
|
||||
* {@link UpdateEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface HasUpdateHandlers<T> extends HasHandlers {
|
||||
/**
|
||||
* Adds a {@link UpdateEvent} handler.
|
||||
*
|
||||
* @param handler the handler
|
||||
* @return the registration for the event
|
||||
*/
|
||||
HandlerRegistration addUpdateHandler(UpdateHandler<T> handler);
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.event.shared.HasHandlers;
|
||||
|
||||
/**
|
||||
* A widget that implements this interface is a public source of
|
||||
* {@link WeekSelectionEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface HasWeekSelectionHandlers<T> extends HasHandlers {
|
||||
/**
|
||||
* Adds a {@link WeekSelectionEvent} handler.
|
||||
*
|
||||
* @param handler the handler
|
||||
* @return the registration for the event
|
||||
*/
|
||||
HandlerRegistration addWeekSelectionHandler(WeekSelectionHandler<T> handler);
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
|
||||
/**
|
||||
* TODO: Complete JavaDoc comments.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class MouseOverEvent<T> extends GwtEvent<MouseOverHandler<T>> {
|
||||
|
||||
/**
|
||||
* Handler type.
|
||||
*/
|
||||
private static Type<MouseOverHandler<?>> TYPE;
|
||||
|
||||
private final T target;
|
||||
private final Object element;
|
||||
|
||||
/**
|
||||
* Fires a open event on all registered handlers in the handler manager.If no
|
||||
* such handlers exist, this method will do nothing.
|
||||
*
|
||||
* @param <T> the target type
|
||||
* @param source the source of the handlers
|
||||
* @param target the dom element
|
||||
*/
|
||||
public static <T> void fire(HasMouseOverHandlers<T> source, T target, Object element) {
|
||||
if (TYPE != null) {
|
||||
MouseOverEvent<T> event = new MouseOverEvent<T>(target, element);
|
||||
source.fireEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
protected MouseOverEvent(T target, Object element) {
|
||||
this.target = target;
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
public T getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public Object getElement() {
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type associated with this event.
|
||||
*
|
||||
* @return returns the handler type
|
||||
*/
|
||||
public static Type<MouseOverHandler<?>> getType() {
|
||||
if (TYPE == null) {
|
||||
TYPE = new Type<MouseOverHandler<?>>();
|
||||
}
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Type<MouseOverHandler<T>> getAssociatedType() {
|
||||
return (Type) TYPE;
|
||||
}
|
||||
|
||||
// Because of type erasure, our static type is
|
||||
// wild carded, yet the "real" type should use our I param.
|
||||
|
||||
@Override
|
||||
protected void dispatch(MouseOverHandler<T> handler) {
|
||||
handler.onMouseOver(this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.EventHandler;
|
||||
|
||||
/**
|
||||
* Handler interface for {@link MouseOverEvent} events.
|
||||
*
|
||||
* @param <T> the type being hovered
|
||||
*/
|
||||
public interface MouseOverHandler<T> extends EventHandler {
|
||||
|
||||
/**
|
||||
* Called when {@link MouseOverEvent} is fired.
|
||||
*
|
||||
* @param event the {@link MouseOverEvent} that was fired
|
||||
*/
|
||||
void onMouseOver(MouseOverEvent<T> event);
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
/**
|
||||
* <code>RollbackException</code> can be thrown to rollback or cancel any
|
||||
* changes made and not yet committed at the time of an Event. <p></p> An
|
||||
* example is when an {@link com.bradrydzewski.gwt.calendar.client.Appointment}
|
||||
* is deleted by the end-user. A DeleteEvent is raised and the change can be
|
||||
* reversed by throwing the RollbackException.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class RollbackException extends Exception {
|
||||
/**
|
||||
* Default empty constructor.
|
||||
*/
|
||||
public RollbackException() {
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
|
||||
/**
|
||||
* TODO: Complete JavaDoc comments.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class TimeBlockClickEvent<T> extends GwtEvent<TimeBlockClickHandler<T>> {
|
||||
|
||||
/**
|
||||
* Handler type.
|
||||
*/
|
||||
private static Type<TimeBlockClickHandler<?>> TYPE;
|
||||
|
||||
|
||||
/**
|
||||
* Fires a open event on all registered handlers in the handler manager.If no
|
||||
* such handlers exist, this method will do nothing.
|
||||
*
|
||||
* @param <T> the target type
|
||||
* @param source the source of the handlers
|
||||
* @param target the target
|
||||
*/
|
||||
public static <T> void fire(HasTimeBlockClickHandlers<T> source, T target) {
|
||||
if (TYPE != null) {
|
||||
TimeBlockClickEvent<T> event = new TimeBlockClickEvent<T>(target);
|
||||
source.fireEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type associated with this event.
|
||||
*
|
||||
* @return returns the handler type
|
||||
*/
|
||||
public static Type<TimeBlockClickHandler<?>> getType() {
|
||||
if (TYPE == null) {
|
||||
TYPE = new Type<TimeBlockClickHandler<?>>();
|
||||
}
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
private final T target;
|
||||
|
||||
/**
|
||||
* Creates a new delete event.
|
||||
*
|
||||
* @param target the ui object being opened
|
||||
*/
|
||||
protected TimeBlockClickEvent(T target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Type<TimeBlockClickHandler<T>> getAssociatedType() {
|
||||
return (Type) TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target.
|
||||
*
|
||||
* @return the target
|
||||
*/
|
||||
public T getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
// Because of type erasure, our static type is
|
||||
// wild carded, yet the "real" type should use our I param.
|
||||
|
||||
@Override
|
||||
protected void dispatch(TimeBlockClickHandler<T> handler) {
|
||||
handler.onTimeBlockClick(this);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.EventHandler;
|
||||
|
||||
/**
|
||||
* Handler interface for {@link DeleteEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface TimeBlockClickHandler<T> extends EventHandler {
|
||||
|
||||
/**
|
||||
* Called when {@link DeleteEvent} is fired.
|
||||
*
|
||||
* @param event the {@link DeleteEvent} that was fired
|
||||
*/
|
||||
void onTimeBlockClick(TimeBlockClickEvent<T> event);
|
||||
}
|
107
src/com/bradrydzewski/gwt/calendar/client/event/UpdateEvent.java
Normal file
107
src/com/bradrydzewski/gwt/calendar/client/event/UpdateEvent.java
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
|
||||
/**
|
||||
* TODO: Complete JavaDoc comments.
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class UpdateEvent<T> extends GwtEvent<UpdateHandler<T>> {
|
||||
|
||||
/**
|
||||
* Handler type.
|
||||
*/
|
||||
private static Type<UpdateHandler<?>> TYPE;
|
||||
|
||||
private boolean cancelled = false;
|
||||
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
|
||||
public void setCancelled(boolean cancelled) {
|
||||
this.cancelled = cancelled;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Fires a open event on all registered handlers in the handler manager.If no
|
||||
* such handlers exist, this method will do nothing.
|
||||
*
|
||||
* @param <T> the target type
|
||||
* @param source the source of the handlers
|
||||
* @param target the target
|
||||
*/
|
||||
public static <T> boolean fire(HasUpdateHandlers<T> source, T target) {
|
||||
if (TYPE != null) {
|
||||
UpdateEvent<T> event = new UpdateEvent<T>(target);
|
||||
source.fireEvent(event);
|
||||
return !event.isCancelled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type associated with this event.
|
||||
*
|
||||
* @return returns the handler type
|
||||
*/
|
||||
public static Type<UpdateHandler<?>> getType() {
|
||||
if (TYPE == null) {
|
||||
TYPE = new Type<UpdateHandler<?>>();
|
||||
}
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
private final T target;
|
||||
|
||||
/**
|
||||
* Creates a new delete event.
|
||||
*
|
||||
* @param target the ui object being opened
|
||||
*/
|
||||
protected UpdateEvent(T target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Type<UpdateHandler<T>> getAssociatedType() {
|
||||
return (Type) TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target.
|
||||
*
|
||||
* @return the target
|
||||
*/
|
||||
public T getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
// Because of type erasure, our static type is
|
||||
// wild carded, yet the "real" type should use our I param.
|
||||
|
||||
@Override
|
||||
protected void dispatch(UpdateHandler<T> handler) {
|
||||
handler.onUpdate(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.EventHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Handler interface for {@link DeleteEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface UpdateHandler<T> extends EventHandler {
|
||||
|
||||
/**
|
||||
* Called when {@link DeleteEvent} is fired.
|
||||
*
|
||||
* @param event the {@link DeleteEvent} that was fired
|
||||
*/
|
||||
void onUpdate(UpdateEvent<T> event);
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.GwtEvent;
|
||||
|
||||
/**
|
||||
* Represents a selection event.
|
||||
*
|
||||
* @param <T>
|
||||
* the type being selected
|
||||
*/
|
||||
public class WeekSelectionEvent<T> extends GwtEvent<WeekSelectionHandler<T>> {
|
||||
|
||||
/**
|
||||
* Handler type.
|
||||
*/
|
||||
private static Type<WeekSelectionHandler<?>> TYPE;
|
||||
|
||||
/**
|
||||
* Fires a selection event on all registered handlers in the handler
|
||||
* manager.If no such handlers exist, this method will do nothing.
|
||||
*
|
||||
* @param <T>
|
||||
* the selected item type
|
||||
* @param source
|
||||
* the source of the handlers
|
||||
* @param selectedItem
|
||||
* the selected item
|
||||
*/
|
||||
public static <T> void fire(HasWeekSelectionHandlers<T> source, T selectedItem) {
|
||||
if (TYPE != null) {
|
||||
WeekSelectionEvent<T> event = new WeekSelectionEvent<T>(
|
||||
selectedItem);
|
||||
source.fireEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type associated with this event.
|
||||
*
|
||||
* @return returns the handler type
|
||||
*/
|
||||
public static Type<WeekSelectionHandler<?>> getType() {
|
||||
if (TYPE == null) {
|
||||
TYPE = new Type<WeekSelectionHandler<?>>();
|
||||
}
|
||||
return TYPE;
|
||||
}
|
||||
|
||||
private final T selectedItem;
|
||||
|
||||
/**
|
||||
* Creates a new selection event.
|
||||
*
|
||||
* @param selectedItem
|
||||
* selected item
|
||||
*/
|
||||
protected WeekSelectionEvent(T selectedItem) {
|
||||
this.selectedItem = selectedItem;
|
||||
}
|
||||
|
||||
// The instance knows its BeforeSelectionHandler is of type I, but the TYPE
|
||||
// field itself does not, so we have to do an unsafe cast here.
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Type<WeekSelectionHandler<T>> getAssociatedType() {
|
||||
return (Type) TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the selected item.
|
||||
*
|
||||
* @return the selected item
|
||||
*/
|
||||
public T getSelectedItem() {
|
||||
return selectedItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatch(WeekSelectionHandler<T> handler) {
|
||||
handler.onSelection(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.event;
|
||||
|
||||
import com.google.gwt.event.shared.EventHandler;
|
||||
|
||||
|
||||
/**
|
||||
* Handler interface for {@link DeleteEvent} events.
|
||||
*
|
||||
* @param <T> the type being opened
|
||||
*/
|
||||
public interface WeekSelectionHandler<T> extends EventHandler {
|
||||
|
||||
/**
|
||||
* Called when {@link DeleteEvent} is fired.
|
||||
*
|
||||
* @param event the {@link DeleteEvent} that was fired
|
||||
*/
|
||||
void onSelection(WeekSelectionEvent<T> event);
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.i18n;
|
||||
|
||||
import com.google.gwt.i18n.client.Messages;
|
||||
|
||||
/**
|
||||
* Defines the Strings that can be localized in gwt-cal.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public interface CalendarConstants extends Messages {
|
||||
/**
|
||||
* Footer for days in the <code>MonthView</code> in which there are more
|
||||
* appointments to display than fit in the day cell.
|
||||
*
|
||||
* @param appointments The number of additional appointments in the day
|
||||
* @return The localized string
|
||||
*/
|
||||
public String more(int appointments);
|
||||
|
||||
/**
|
||||
* The localized text label for 12 p.m.
|
||||
*
|
||||
* @return The label for the noon
|
||||
*/
|
||||
public String noon();
|
||||
|
||||
/**
|
||||
* String representing AM. For certain locales this
|
||||
* will be null.
|
||||
*
|
||||
* @return AM string
|
||||
*/
|
||||
public String am();
|
||||
|
||||
/**
|
||||
* String representing AM. For certain locales this
|
||||
* will be null.
|
||||
*
|
||||
* @return PM string
|
||||
*/
|
||||
public String pm();
|
||||
|
||||
|
||||
/**
|
||||
* String used to format time in the <code>DayView</code>
|
||||
* components timeline. Example: time is formatted in the US as h AM,
|
||||
* and is formatted in French HH:00.
|
||||
*
|
||||
* @return The localized time format for the DayView
|
||||
*/
|
||||
public String timeFormat();
|
||||
|
||||
/**
|
||||
* Each column in the <code>DayView</code> represents a date in time, and
|
||||
* displays the date in its header (i.e. Wed, Jan 15). This property
|
||||
* provides the pattern to format the date.
|
||||
*
|
||||
* @return The localized time format for the DayView
|
||||
*/
|
||||
public String dateFormat();
|
||||
|
||||
/**
|
||||
* Each column in the <code>MonthView</code> represents a day of the week,
|
||||
* and displays the day of the week in its header (i.e. Mon, Tue, Wed). This
|
||||
* property provides the pattern to format the day of the week.
|
||||
*
|
||||
* @return The pattern to format the names of the days in the month view
|
||||
*/
|
||||
public String weekdayFormat();
|
||||
|
||||
/**
|
||||
* Returns the pattern to format the days in a month.
|
||||
*
|
||||
* @return The pattern to format the names/numbers of days in a month
|
||||
*/
|
||||
public String dayOfMonthFormat();
|
||||
|
||||
/**
|
||||
* Returns what the first day of the week is; e.g., SUNDAY in the U.S.,
|
||||
* MONDAY in France.
|
||||
*
|
||||
* @return The text representing the first day of the week, zero-based
|
||||
* (Sunday is 0, Monday is 1, Tuesday is 2, etc.)
|
||||
*/
|
||||
public String firstDayOfWeek();
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
noon=Noon
|
||||
more=+{0} more
|
||||
dayOfMonthFormat=d
|
||||
timeFormat=h
|
||||
dateFormat=EEE, MMM d
|
||||
weekdayFormat=EEE
|
||||
am=AM
|
||||
pm=PM
|
||||
firstDayOfWeek=0
|
@ -0,0 +1,105 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
|
||||
/**
|
||||
* Contains common properties and behavior for layout descriptions that can be
|
||||
* "stacked" on top of each month view's week.
|
||||
*
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class AppointmentLayoutDescription {
|
||||
/**
|
||||
* The layer order (in a stack-like arrangement)assigned to this description
|
||||
* by the <code>AppointmentStackingManager</code> when arranging the
|
||||
* descriptions on the top of a week.
|
||||
*/
|
||||
private int stackOrder = 0;
|
||||
|
||||
/**
|
||||
* The start day of the described <code>Appointment</code> when laid on the
|
||||
* top of one of the weeks while visualizing a month through the
|
||||
* <code>MonthView</code>.
|
||||
*/
|
||||
private int fromWeekDay = 0;
|
||||
|
||||
/**
|
||||
* The end day of the described <code>Appointment</code> when laid on the top
|
||||
* of one of the weeks while visualizing a month through the
|
||||
* <code>MonthView</code>.
|
||||
*/
|
||||
private int toWeekDay = 0;
|
||||
|
||||
/**
|
||||
* The underlying <code>Appointment</code> whose details will be displayed
|
||||
* through the <code>MonthView</code>.
|
||||
*/
|
||||
private Appointment appointment = null;
|
||||
|
||||
|
||||
public AppointmentLayoutDescription(int fromWeekDay, int toWeekDay,
|
||||
Appointment appointment) {
|
||||
this.toWeekDay = toWeekDay;
|
||||
this.fromWeekDay = fromWeekDay;
|
||||
this.appointment = appointment;
|
||||
}
|
||||
|
||||
public AppointmentLayoutDescription(int weekDay,
|
||||
Appointment appointment) {
|
||||
this(weekDay, weekDay, appointment);
|
||||
}
|
||||
|
||||
public boolean overlapsWithRange(int from, int to) {
|
||||
return fromWeekDay >= from && fromWeekDay <= to ||
|
||||
fromWeekDay <= from && toWeekDay >= from;
|
||||
}
|
||||
|
||||
public void setStackOrder(int stackOrder) {
|
||||
this.stackOrder = stackOrder;
|
||||
}
|
||||
|
||||
public int getStackOrder() {
|
||||
return stackOrder;
|
||||
}
|
||||
|
||||
public int getWeekStartDay() {
|
||||
return fromWeekDay;
|
||||
}
|
||||
|
||||
public int getWeekEndDay() {
|
||||
return toWeekDay;
|
||||
}
|
||||
|
||||
public boolean spansMoreThanADay() {
|
||||
return fromWeekDay != toWeekDay;
|
||||
}
|
||||
|
||||
public AppointmentLayoutDescription split() {
|
||||
AppointmentLayoutDescription secondPart = null;
|
||||
if (spansMoreThanADay()) {
|
||||
secondPart =
|
||||
new AppointmentLayoutDescription(fromWeekDay + 1, toWeekDay,
|
||||
appointment);
|
||||
this.toWeekDay = this.fromWeekDay;
|
||||
} else {
|
||||
secondPart = this;
|
||||
}
|
||||
return secondPart;
|
||||
}
|
||||
|
||||
|
||||
public Appointment getAppointment() {
|
||||
return appointment;
|
||||
}
|
||||
|
||||
public void setAppointment(Appointment appointment) {
|
||||
this.appointment = appointment;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "AppointmentLayoutDescription{" + "stackOrder=" + stackOrder
|
||||
+ ", fromWeekDay=" + fromWeekDay + ", toWeekDay=" + toWeekDay
|
||||
+ ", appointment=[" + appointment.getTitle() + "]@"
|
||||
+ appointment.hashCode() + '}';
|
||||
}
|
||||
}
|
@ -0,0 +1,258 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Manages the <code>AppointmentLayoutDescription</code> in a stack-like
|
||||
* structure arranged in layers. Layers are <code>0</code>-based (1nd. layer has
|
||||
* an index of 0, 2nd. has an index of 1).
|
||||
*
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class AppointmentStackingManager {
|
||||
|
||||
/**
|
||||
* The highest layer index that has been allocated by this manager.
|
||||
*/
|
||||
private int highestLayer = 0;
|
||||
|
||||
/**
|
||||
* The collection of <code>AppointmentLayoutDescription</code>s grouped by by
|
||||
* layer (map key).
|
||||
*/
|
||||
private HashMap<Integer, ArrayList<AppointmentLayoutDescription>>
|
||||
layeredDescriptions =
|
||||
new HashMap<Integer, ArrayList<AppointmentLayoutDescription>>();
|
||||
|
||||
private int layerOverflowLimit = Integer.MAX_VALUE;
|
||||
|
||||
public void setLayerOverflowLimit(int layerOverflowLimit) {
|
||||
this.layerOverflowLimit = layerOverflowLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Associates the provided <code>description</code> to the first available
|
||||
* layer in the collection administered by this manager. This manager will
|
||||
* look up in the stack of layers (from lowest index to highest index) until
|
||||
* a layer that <em>does not have</em> any <code>AppointmentLayoutDescription</code>s
|
||||
* that overlap with the days that the description's appointment spans.
|
||||
*
|
||||
* @param description An appointment description object that can be laid on a
|
||||
* layer
|
||||
*/
|
||||
public void assignLayer(AppointmentLayoutDescription description) {
|
||||
boolean layerAssigned;
|
||||
int currentlyInspectedLayer = 0;
|
||||
do {
|
||||
initLayer(currentlyInspectedLayer);
|
||||
layerAssigned = assignLayer(currentlyInspectedLayer, description);
|
||||
currentlyInspectedLayer++;
|
||||
} while (!layerAssigned);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowest layer index that is available on the specified
|
||||
* <code>day</code>.
|
||||
*
|
||||
* @param day The day index for which the lowest layer index will be
|
||||
* attempted to identify
|
||||
* @return An integer representing the index of the layer (zero-based) for
|
||||
* which an single day <code>Appointment</code> can be displayed on.
|
||||
*/
|
||||
public int lowestLayerIndex(int day) {
|
||||
return (nextLowestLayerIndex(day, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the lowest layer index <em>higher than</em> <code>fromLayer</code>
|
||||
* that is available on the specified <code>day</code>.
|
||||
*
|
||||
* @param day The day index for which the lowest layer index will be
|
||||
* attempted to identify found
|
||||
* @param fromLayer The layer index <em>after</em> which the search for next
|
||||
* available layer should be started from
|
||||
* @return An integer representing the index of the layer (zero-based) for
|
||||
* which an single day <code>Appointment</code> can be displayed on.
|
||||
*/
|
||||
public int nextLowestLayerIndex(int day, int fromLayer) {
|
||||
boolean layerFound = false;
|
||||
int currentlyInspectedLayer = fromLayer;
|
||||
do {
|
||||
if (isLayerAllocated(currentlyInspectedLayer)) {
|
||||
if (overlapsWithDescriptionInLayer(
|
||||
layeredDescriptions.get(currentlyInspectedLayer), day,
|
||||
day)) {
|
||||
currentlyInspectedLayer++;
|
||||
} else {
|
||||
layerFound = true;
|
||||
}
|
||||
} else {
|
||||
layerFound = true;
|
||||
}
|
||||
|
||||
} while (!layerFound);
|
||||
return currentlyInspectedLayer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the <code>AppointmentLayoutDescription</code>s in the
|
||||
* specified layer.
|
||||
*
|
||||
* @param layerIndex The index of a layer for which descriptions will be
|
||||
* returned
|
||||
* @return The collection of appointment descriptions in the layer,
|
||||
* <code>null</code> if no appointment has been allocated for the
|
||||
* layer at all
|
||||
*/
|
||||
public ArrayList<AppointmentLayoutDescription> getDescriptionsInLayer(
|
||||
int layerIndex) {
|
||||
return layeredDescriptions.get(layerIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the range defined by <code>start</code>-<code>end</code>
|
||||
* overlaps with any of the appointment descriptions in
|
||||
* <code>layerDescriptions</code>.
|
||||
*
|
||||
* @param layerDescriptions All the <code>AppointmentLayoutDescription</code>
|
||||
* in a single layer.
|
||||
* @param start The first day of the week in the range to test
|
||||
* @param end The last day of the week in the range to test
|
||||
* @return <code>true</code> if any appointment description in
|
||||
* <code>layerDescriptions</code> overlaps with the specified range,
|
||||
* <code>false</code> otherwise.
|
||||
*/
|
||||
private boolean overlapsWithDescriptionInLayer(
|
||||
ArrayList<AppointmentLayoutDescription> layerDescriptions, int start,
|
||||
int end) {
|
||||
if (layerDescriptions != null) {
|
||||
for (AppointmentLayoutDescription description : layerDescriptions) {
|
||||
if (description.overlapsWithRange(start, end)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean assignLayer(int layer,
|
||||
AppointmentLayoutDescription description) {
|
||||
ArrayList<AppointmentLayoutDescription> layerDescriptions = layeredDescriptions
|
||||
.get(layer);
|
||||
|
||||
boolean assigned = false;
|
||||
if (!overlapsWithDescriptionInLayer(layerDescriptions,
|
||||
description.getWeekStartDay(), description.getWeekEndDay())) {
|
||||
highestLayer = Math.max(highestLayer, layer);
|
||||
if (layer > layerOverflowLimit && description.spansMoreThanADay()) {
|
||||
AppointmentLayoutDescription split = description.split();
|
||||
layerDescriptions.add(description);
|
||||
assignLayer(split);
|
||||
} else {
|
||||
layerDescriptions.add(description);
|
||||
}
|
||||
|
||||
assigned = true;
|
||||
}
|
||||
return assigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether a specific layerIndex with index <code>layerIndex</code>
|
||||
* has been allocated in the <code>layeredDescriptions</code> map.
|
||||
*
|
||||
* @param layerIndex The index of a layer to verify
|
||||
* @return <code>true</code> if the <code>layeredDescriptions</code> map has
|
||||
* an entry (<code>List<AppointmentLayoutDescription></code>)
|
||||
* for the <code>layerIndex</code>.
|
||||
*/
|
||||
private boolean isLayerAllocated(int layerIndex) {
|
||||
return layeredDescriptions.get(layerIndex) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the collection of descriptions for the layer with the
|
||||
* specified <code>layerIndex</code>.
|
||||
*
|
||||
* @param layerIndex The index of a layer to initialize
|
||||
*/
|
||||
private void initLayer(int layerIndex) {
|
||||
if (!isLayerAllocated(layerIndex)) {
|
||||
layeredDescriptions.put(layerIndex,
|
||||
new ArrayList<AppointmentLayoutDescription>());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of appointments (multi-day or all-day, as that's the
|
||||
* type of appointment that the stacking manager deals with only) that
|
||||
* exceeded the <code>layerOverflowLimit</code> value when they were
|
||||
* stacked.
|
||||
*
|
||||
* @param day The day to perform the count
|
||||
* @return The number of days that got a layer higher than the configured
|
||||
* <code>layerOverflowLimit</code> layer, if there were any
|
||||
*/
|
||||
public int multidayAppointmentsOverLimitOn(int day) {
|
||||
int count = 0;
|
||||
for (int layer = 0; layer <= highestLayer; layer++) {
|
||||
ArrayList<AppointmentLayoutDescription> descriptions =
|
||||
layeredDescriptions.get(layer);
|
||||
if (descriptions != null) {
|
||||
for (AppointmentLayoutDescription description : descriptions) {
|
||||
if (layer > layerOverflowLimit &&
|
||||
description.overlapsWithRange(day, day)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether there are <em>any</em> appointments that encompass the
|
||||
* specified <code>day</code>.
|
||||
*
|
||||
* @param day The day to test for appointments
|
||||
* @return <code>true</code> if there are any descriptions in any layer for
|
||||
* the specified <code>day</code>.
|
||||
*/
|
||||
public boolean areThereAppointmentsOn(int day) {
|
||||
boolean thereAre = false;
|
||||
for (int layersIndex = 0; layersIndex <= highestLayer; layersIndex++) {
|
||||
ArrayList<AppointmentLayoutDescription> layerDescriptions =
|
||||
layeredDescriptions.get(layersIndex);
|
||||
if (overlapsWithDescriptionInLayer(layerDescriptions, day, day)) {
|
||||
thereAre = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return thereAre;
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
StringBuilder managerState = new StringBuilder();
|
||||
for (int i = 0; i <= highestLayer; i++) {
|
||||
ArrayList<AppointmentLayoutDescription> descriptions =
|
||||
this.getDescriptionsInLayer(i);
|
||||
if (descriptions == null) continue;
|
||||
for (AppointmentLayoutDescription desc : descriptions) {
|
||||
managerState.append("[").append(i).append("]");
|
||||
for (int before = 0; before < desc.getWeekStartDay(); before++) {
|
||||
managerState.append("_");
|
||||
}
|
||||
for (int dur = desc.getWeekStartDay(); dur <= desc.getWeekEndDay();
|
||||
dur++) {
|
||||
managerState.append("X");
|
||||
}
|
||||
for (int after = desc.getWeekEndDay(); after < 6; after++) {
|
||||
managerState.append("_");
|
||||
}
|
||||
managerState.append(" ->").append(desc).append("\n");
|
||||
}
|
||||
}
|
||||
return managerState.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.google.gwt.user.client.ui.FocusPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
|
||||
/**
|
||||
* A panel used to render an <code>Appointment</code> in a
|
||||
* <code>MonthView</code>. <p> Through an association to a domain-model
|
||||
* <code>Appointment</code>, <code>AppointmentWidget</code>s allow displaying
|
||||
* the appointment details <em>and</em> to capture mouse and keyboard events.
|
||||
* </p>
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class AppointmentWidget extends FocusPanel {
|
||||
/**
|
||||
* The underlying <code>Appointment</code> represented by this panel.
|
||||
*/
|
||||
private Appointment appointment;
|
||||
|
||||
/**
|
||||
* Creates an <code>AppointmentWidget</code> with a reference to the provided
|
||||
* <code>appointment</code>.
|
||||
*
|
||||
* @param appointment The appointment to be displayed through this panel
|
||||
* widget
|
||||
*/
|
||||
public AppointmentWidget(Appointment appointment) {
|
||||
this.appointment = appointment;
|
||||
Label titleLabel = new Label();
|
||||
titleLabel.getElement().setInnerHTML(this.appointment.getTitle());
|
||||
this.add(titleLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>Appointment</code> this panel represents/is associated
|
||||
* to.
|
||||
*
|
||||
* @return The domain model appointment rendered through this panel
|
||||
*/
|
||||
public Appointment getAppointment() {
|
||||
return appointment;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
/**
|
||||
* Indicates whether the presence of an <code>Appointment</code> that spans
|
||||
* multiple weeks in a month view is the <em>first</em>, second or before the
|
||||
* last, or the <em>last</em>.
|
||||
*
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public enum AppointmentWidgetParts {
|
||||
FIRST_WEEK, IN_BETWEEN, LAST_WEEK
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
|
||||
/**
|
||||
* Contains the calculated layout description of all <code>Appointment</code>s
|
||||
* in single day part of a week row in a <code>MonthView</code>.
|
||||
* <p></p><strong>Note:</strong> A <code>DayLayoutDescription</code> is not
|
||||
* aware of <em>multi-day</em> <code>Appointment</code>s that might span the day
|
||||
* represented by this description.
|
||||
*
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class DayLayoutDescription {
|
||||
/**
|
||||
* The list of <em>simple</em> appointments (not multiday, not all-day) in
|
||||
* this single day.
|
||||
*/
|
||||
private List<Appointment> appointments = new ArrayList<Appointment>();
|
||||
|
||||
/**
|
||||
* The index of the represented day in the corresponding parent week.
|
||||
*/
|
||||
private int dayIndex = -1;
|
||||
|
||||
public DayLayoutDescription(int dayIndex) {
|
||||
this.dayIndex = dayIndex;
|
||||
}
|
||||
|
||||
public List<Appointment> getAppointments() {
|
||||
return appointments;
|
||||
}
|
||||
|
||||
public int getTotalAppointmentCount() {
|
||||
return appointments.size();
|
||||
}
|
||||
|
||||
public void addAppointment(Appointment appointment) {
|
||||
if (!appointment.isMultiDay()) {
|
||||
appointments.add(appointment);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
"Attempted to add a multiday appointment to a single day description");
|
||||
}
|
||||
}
|
||||
|
||||
public int getDayIndex() {
|
||||
return dayIndex;
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
|
||||
/**
|
||||
* Describes the layout for all appointments in all the weeks displayed in a
|
||||
* <code>MonthView</code>. This class is responsible for the distribution of the
|
||||
* appointments over the multiple weeks they possibly span.
|
||||
*
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class MonthLayoutDescription {
|
||||
|
||||
private Date calendarFirstDay = null;
|
||||
|
||||
private Date calendarLastDay = null;
|
||||
|
||||
private WeekLayoutDescription[] weeks = new WeekLayoutDescription[6];
|
||||
|
||||
public MonthLayoutDescription(Date calendarFirstDay,
|
||||
int monthViewRequiredRows,
|
||||
List<Appointment> appointments, int maxLayer) {
|
||||
this.calendarFirstDay = calendarFirstDay;
|
||||
this.calendarLastDay =
|
||||
calculateLastDate(calendarFirstDay, monthViewRequiredRows);
|
||||
placeAppointments(appointments, maxLayer);
|
||||
}
|
||||
|
||||
public MonthLayoutDescription(Date calendarFirstDay,
|
||||
int monthViewRequiredRows,
|
||||
List<Appointment> appointments) {
|
||||
this(calendarFirstDay, monthViewRequiredRows,
|
||||
appointments, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
private void initWeek(int weekIndex, int maxLayer) {
|
||||
if (weeks[weekIndex] == null) {
|
||||
weeks[weekIndex] = new WeekLayoutDescription(calendarFirstDay,
|
||||
calendarLastDay,
|
||||
maxLayer);
|
||||
}
|
||||
}
|
||||
|
||||
private void placeAppointments(List<Appointment> appointments,
|
||||
int maxLayer) {
|
||||
|
||||
for (Appointment appointment : appointments) {
|
||||
if (overlapsWithMonth(appointment, calendarFirstDay,
|
||||
calendarLastDay)) {
|
||||
int startWeek =
|
||||
calculateWeekFor(appointment.getStart(), calendarFirstDay);
|
||||
|
||||
/* Place appointments only in this month */
|
||||
if (startWeek >= 0 && startWeek < weeks.length) {
|
||||
initWeek(startWeek, maxLayer);
|
||||
if (appointment.isMultiDay() || appointment.isAllDay()) {
|
||||
positionMultidayAppointment(startWeek, appointment, maxLayer);
|
||||
} else {
|
||||
weeks[startWeek].addAppointment(appointment);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMultiWeekAppointment(int startWeek, int endWeek) {
|
||||
return startWeek != endWeek;
|
||||
}
|
||||
|
||||
private void positionMultidayAppointment(int startWeek,
|
||||
Appointment appointment, int maxLayer) {
|
||||
int endWeek = calculateWeekFor(appointment.getEnd(), calendarFirstDay);
|
||||
|
||||
initWeek(endWeek, maxLayer);
|
||||
if (isMultiWeekAppointment(startWeek, endWeek)) {
|
||||
distributeOverWeeks(startWeek, endWeek, appointment, maxLayer);
|
||||
} else {
|
||||
weeks[startWeek].addMultiDayAppointment(appointment);
|
||||
}
|
||||
}
|
||||
|
||||
private void distributeOverWeeks(int startWeek, int endWeek,
|
||||
Appointment appointment, int maxLayer) {
|
||||
weeks[startWeek].addMultiWeekAppointment(appointment,
|
||||
AppointmentWidgetParts.FIRST_WEEK);
|
||||
for (int week = startWeek + 1; week < endWeek; week++) {
|
||||
initWeek(week, maxLayer);
|
||||
weeks[week].addMultiWeekAppointment(appointment,
|
||||
AppointmentWidgetParts.IN_BETWEEN);
|
||||
}
|
||||
if (startWeek < endWeek) {
|
||||
initWeek(endWeek, maxLayer);
|
||||
weeks[endWeek].addMultiWeekAppointment(appointment,
|
||||
AppointmentWidgetParts.LAST_WEEK);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean overlapsWithMonth(Appointment appointment,
|
||||
Date calendarFirstDate, Date calendarLastDate) {
|
||||
return !(appointment.getStart().before(calendarFirstDate)
|
||||
&& appointment.getEnd().before(calendarFirstDate)
|
||||
|| appointment.getStart().after(calendarLastDate)
|
||||
&& appointment.getEnd().after(calendarLastDate));
|
||||
}
|
||||
|
||||
private int calculateWeekFor(Date testDate, Date calendarFirstDate) {
|
||||
//fix for issue 66. differenceInDays returns abs value, causing problems
|
||||
if(testDate.before(calendarFirstDate))
|
||||
return 0;
|
||||
|
||||
int week = (int) Math.floor(
|
||||
DateUtils.differenceInDays(
|
||||
testDate, calendarFirstDate) / 7d);
|
||||
|
||||
return Math.min(week, weeks.length - 1);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private Date calculateLastDate(final Date startDate, int weeks) {
|
||||
int daysInMonthGrid = weeks * 7;
|
||||
Date endDate = (Date) startDate.clone();
|
||||
endDate.setDate(endDate.getDate() + daysInMonthGrid - 1);
|
||||
// fix for issue 164: The endDate is at the end of the day
|
||||
endDate.setHours(23);
|
||||
endDate.setMinutes(59);
|
||||
endDate.setSeconds(59);
|
||||
return endDate;
|
||||
}
|
||||
|
||||
public WeekLayoutDescription[] getWeekDescriptions() {
|
||||
return weeks;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,764 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2009 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
import static com.bradrydzewski.gwt.calendar.client.DateUtils.moveOneDayForward;
|
||||
import static com.bradrydzewski.gwt.calendar.client.monthview.MonthViewDateUtils.firstDateShownInAMonthView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.allen_sauer.gwt.dnd.client.DragEndEvent;
|
||||
import com.allen_sauer.gwt.dnd.client.DragHandler;
|
||||
import com.allen_sauer.gwt.dnd.client.DragStartEvent;
|
||||
import com.allen_sauer.gwt.dnd.client.PickupDragController;
|
||||
import com.allen_sauer.gwt.dnd.client.VetoDragException;
|
||||
import com.allen_sauer.gwt.dnd.client.drop.MonthViewDropController;
|
||||
import com.allen_sauer.gwt.dnd.client.drop.MonthViewPickupDragController;
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarFormat;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarSettings.Click;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarView;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarWidget;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasDaySelectionHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasWeekSelectionHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.FormattingUtil;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.Window;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
import com.google.gwt.user.client.ui.HorizontalPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* A CalendarView that displays appointments for a given month. The Month is
|
||||
* displayed in a grid-style view where cells represents days, columns
|
||||
* represents days of the week (i.e. Monday, Tuesday, etc.) and rows represent a
|
||||
* full week (Sunday through Saturday).
|
||||
* <p/>
|
||||
* <p/>
|
||||
* <h3>CSS Style Rules</h3> <ul class='css'>
|
||||
* <li>.gwt-cal-MonthView { }</li>
|
||||
* <li>.dayCell { cell that represents a day }</li>
|
||||
* <li>.dayCell-today { cell that represents today }</li>
|
||||
* <li>.dayCell-disabled { cell's day falls outside the month }</li>
|
||||
* <li>.dayCell-today-disabled { cell represents today, falls outside the month
|
||||
* }</li>
|
||||
* <li>.dayCellLabel { header for the cell }</li>
|
||||
* <li>.dayCellLabel-today { cell represents today }</li>
|
||||
* <li>.dayCellLabel-disabled { cell's day falls outside the month }</li>
|
||||
* <li>.dayCellLabel-today-disabled { cell represents today, falls outside the
|
||||
* month }</li>
|
||||
* <li>.weekDayLabel { label for the days of the week }</li> </ul>
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @since 0.9.0
|
||||
*/
|
||||
public class MonthView extends CalendarView implements HasWeekSelectionHandlers<Date>, HasDaySelectionHandlers<Date> {
|
||||
|
||||
public static final Comparator<Appointment> APPOINTMENT_COMPARATOR = new Comparator<Appointment>() {
|
||||
|
||||
public int compare(Appointment a1, Appointment a2) {
|
||||
int compare = Boolean.valueOf(a2.isMultiDay()).compareTo(
|
||||
a1.isMultiDay());
|
||||
|
||||
if (compare == 0) {
|
||||
compare = a1.getStart().compareTo(a2.getStart());
|
||||
}
|
||||
|
||||
if (compare == 0) {
|
||||
compare = a2.getEnd().compareTo(a1.getEnd());
|
||||
}
|
||||
|
||||
return compare;
|
||||
}
|
||||
};
|
||||
|
||||
private static final int DAYS_IN_A_WEEK = 7;
|
||||
private final static String MONTH_VIEW = "gwt-cal-MonthView";
|
||||
private final static String CANVAS_STYLE = "canvas";
|
||||
private final static String GRID_STYLE = "grid";
|
||||
private final static String CELL_STYLE = "dayCell";
|
||||
private final static String MORE_LABEL_STYLE = "moreAppointments";
|
||||
private final static String CELL_HEADER_STYLE = "dayCellLabel";
|
||||
private final static String WEEKDAY_LABEL_STYLE = "weekDayLabel";
|
||||
private final static String WEEKNUMBER_LABEL_STYLE = "weekNumberLabel";
|
||||
|
||||
|
||||
/**
|
||||
* List of appointment panels drawn on the month view canvas.
|
||||
*/
|
||||
private ArrayList<AppointmentWidget> appointmentsWidgets = new ArrayList<AppointmentWidget>();
|
||||
|
||||
/**
|
||||
* All appointments are placed on this canvas and arranged.
|
||||
*/
|
||||
private AbsolutePanel appointmentCanvas = new AbsolutePanel();
|
||||
|
||||
/**
|
||||
* All "+ n more" Labels, mapped to its cell in the MonthView Grid.
|
||||
*/
|
||||
private HashMap<Element, Integer> moreLabels = new HashMap<Element, Integer>();
|
||||
private ArrayList<Label> dayLabels = new ArrayList<Label>();
|
||||
private ArrayList<Widget> dayPanels = new ArrayList<Widget>();
|
||||
|
||||
/**
|
||||
* The first date displayed on the MonthView (1st cell.) This date is not
|
||||
* necessarily the first date of the month as the month view will sometimes
|
||||
* display days from the adjacent months because of the number of days
|
||||
* fitting in the visible grid.
|
||||
*/
|
||||
private Date firstDateDisplayed;
|
||||
|
||||
/**
|
||||
* Grid that makes up the days and weeks of the MonthView.
|
||||
*/
|
||||
private FlexTable monthCalendarGrid = new FlexTable();
|
||||
|
||||
/**
|
||||
* The number of rows required to display the entire month in grid format.
|
||||
* Although most months span a total of five weeks, there are some months
|
||||
* that span six weeks.
|
||||
*/
|
||||
private int monthViewRequiredRows = 5;
|
||||
|
||||
/**
|
||||
* List of <code>AppointmentWidget</code>s that are associated to the
|
||||
* currently selected <code>Appointment</code> appointment.
|
||||
*/
|
||||
private ArrayList<AppointmentWidget> selectedAppointmentWidgets = new ArrayList<AppointmentWidget>();
|
||||
|
||||
private PickupDragController dragController = null;
|
||||
|
||||
private MonthViewDropController monthViewDropController = null;
|
||||
|
||||
private MonthViewStyleManager styleManager = GWT.create(MonthViewStyleManager.class);
|
||||
|
||||
/**
|
||||
* This method is called when the MonthView is attached to the Calendar and
|
||||
* displayed. This is where all components are configured and added to the
|
||||
* RootPanel.
|
||||
*/
|
||||
public void attach(CalendarWidget widget) {
|
||||
super.attach(widget);
|
||||
|
||||
calendarWidget.addToRootPanel(monthCalendarGrid);
|
||||
monthCalendarGrid.setCellPadding(0);
|
||||
monthCalendarGrid.setBorderWidth(0);
|
||||
monthCalendarGrid.setCellSpacing(0);
|
||||
monthCalendarGrid.setStyleName(GRID_STYLE);
|
||||
|
||||
calendarWidget.addToRootPanel(appointmentCanvas);
|
||||
appointmentCanvas.setStyleName(CANVAS_STYLE);
|
||||
|
||||
selectedAppointmentWidgets.clear();
|
||||
|
||||
if (dragController == null) {
|
||||
dragController = new MonthViewPickupDragController(appointmentCanvas, true);
|
||||
dragController.addDragHandler(new DragHandler() {
|
||||
|
||||
public void onDragEnd(DragEndEvent event) {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable).getAppointment();
|
||||
|
||||
calendarWidget.setCommittedAppointment(appt);
|
||||
calendarWidget.fireUpdateEvent(appt);
|
||||
}
|
||||
|
||||
public void onDragStart(DragStartEvent event) {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable).getAppointment();
|
||||
calendarWidget.setRollbackAppointment(appt.clone());
|
||||
}
|
||||
|
||||
public void onPreviewDragEnd(DragEndEvent event)
|
||||
throws VetoDragException {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
public void onPreviewDragStart(DragStartEvent event)
|
||||
throws VetoDragException {
|
||||
// do nothing
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Need to re-set appointmentCanvas to position:absolute because gwt-dnd
|
||||
* will set it to relative, but then the layout gets f***ed up
|
||||
*/
|
||||
DOM.setStyleAttribute(appointmentCanvas.getElement(), "position",
|
||||
"absolute");
|
||||
|
||||
dragController.setBehaviorDragStartSensitivity(5);
|
||||
dragController.setBehaviorDragProxy(true);
|
||||
|
||||
// instantiate our drop controller
|
||||
monthViewDropController = new MonthViewDropController(
|
||||
appointmentCanvas, monthCalendarGrid);
|
||||
dragController.registerDropController(monthViewDropController);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a Layout and arranges all appointments on the MonthView's
|
||||
* appointment canvas.
|
||||
*/
|
||||
@Override
|
||||
public void doLayout() {
|
||||
// Clear all existing appointments
|
||||
appointmentCanvas.clear();
|
||||
monthCalendarGrid.clear();
|
||||
appointmentsWidgets.clear();
|
||||
moreLabels.clear();
|
||||
dayLabels.clear();
|
||||
dayPanels.clear();
|
||||
selectedAppointmentWidgets.clear();
|
||||
while (monthCalendarGrid.getRowCount() > 0) {
|
||||
monthCalendarGrid.removeRow(0);
|
||||
}
|
||||
|
||||
// Rebuild the month grid
|
||||
buildCalendarGrid();
|
||||
|
||||
// (Re)calculate some variables
|
||||
calculateCellHeight();
|
||||
calculateCellAppointments();
|
||||
|
||||
// set variables needed by the drop controller
|
||||
// monthViewDropController.setDayHeaderHeight(calculatedDayHeaderHeight);
|
||||
monthViewDropController.setDaysPerWeek(DAYS_IN_A_WEEK);
|
||||
// monthViewDropController.setWeekdayHeaderHeight(calculatedWeekDayHeaderHeight);
|
||||
monthViewDropController.setWeeksPerMonth(monthViewRequiredRows);
|
||||
monthViewDropController.setFirstDateDisplayed(firstDateDisplayed);
|
||||
|
||||
// Sort the appointments
|
||||
// TODO: don't re-sort the appointment unless necessary
|
||||
Collections.sort(calendarWidget.getAppointments(),
|
||||
APPOINTMENT_COMPARATOR);
|
||||
// Distribute appointments
|
||||
MonthLayoutDescription monthLayoutDescription = new
|
||||
MonthLayoutDescription(
|
||||
firstDateDisplayed, monthViewRequiredRows,
|
||||
calendarWidget.getAppointments(),
|
||||
calculatedCellAppointments - 1);
|
||||
|
||||
int dayIndex = 0;
|
||||
for (int row = 0; row < monthCalendarGrid.getRowCount() - 1; row++) {
|
||||
for (int col = 0; col < DAYS_IN_A_WEEK; col++) {
|
||||
Widget lbl = dayPanels.get(dayIndex);
|
||||
placeDayLabelInGrid(lbl, col, row);
|
||||
dayIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the layouts for each week in the month
|
||||
WeekLayoutDescription[] weeks = monthLayoutDescription
|
||||
.getWeekDescriptions();
|
||||
for (int weekOfMonth = 0; weekOfMonth < weeks.length
|
||||
&& weekOfMonth < monthViewRequiredRows; weekOfMonth++) {
|
||||
WeekLayoutDescription weekDescription = weeks[weekOfMonth];
|
||||
if (weekDescription != null) {
|
||||
layOnTopOfTheWeekHangingAppointments(
|
||||
weekDescription, weekOfMonth);
|
||||
layOnWeekDaysAppointments(weekDescription, weekOfMonth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void layOnTopOfTheWeekHangingAppointments(
|
||||
WeekLayoutDescription weekDescription, int weekOfMonth) {
|
||||
AppointmentStackingManager weekTopElements
|
||||
= weekDescription.getTopAppointmentsManager();
|
||||
for (int layer = 0; layer < calculatedCellAppointments; layer++) {
|
||||
|
||||
ArrayList<AppointmentLayoutDescription> descriptionsInLayer
|
||||
= weekTopElements.getDescriptionsInLayer(layer);
|
||||
|
||||
if (descriptionsInLayer == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (AppointmentLayoutDescription weekTopElement : descriptionsInLayer) {
|
||||
layOnAppointment(weekTopElement.getAppointment(),
|
||||
weekTopElement.getWeekStartDay(), weekTopElement
|
||||
.getWeekEndDay(), weekOfMonth, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void layOnWeekDaysAppointments(WeekLayoutDescription week,
|
||||
int weekOfMonth) {
|
||||
|
||||
AppointmentStackingManager topAppointmentManager = week
|
||||
.getTopAppointmentsManager();
|
||||
|
||||
for (int dayOfWeek = 0; dayOfWeek < DAYS_IN_A_WEEK; dayOfWeek++) {
|
||||
DayLayoutDescription dayAppointments = week
|
||||
.getDayLayoutDescription(dayOfWeek);
|
||||
|
||||
int appointmentLayer =
|
||||
topAppointmentManager.lowestLayerIndex(dayOfWeek);
|
||||
|
||||
if (dayAppointments != null) {
|
||||
int count = dayAppointments.getAppointments().size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
Appointment appointment
|
||||
= dayAppointments.getAppointments().get(i);
|
||||
appointmentLayer = topAppointmentManager
|
||||
.nextLowestLayerIndex(dayOfWeek,
|
||||
appointmentLayer);
|
||||
if (appointmentLayer > calculatedCellAppointments - 1) {
|
||||
int remaining = count + topAppointmentManager.multidayAppointmentsOverLimitOn(dayOfWeek) - i;
|
||||
if (remaining == 1) {
|
||||
layOnAppointment(appointment, dayOfWeek, dayOfWeek,
|
||||
weekOfMonth, appointmentLayer);
|
||||
} else {
|
||||
layOnNMoreLabel(remaining, dayOfWeek, weekOfMonth);
|
||||
}
|
||||
break;
|
||||
}
|
||||
layOnAppointment(appointment, dayOfWeek, dayOfWeek,
|
||||
weekOfMonth, appointmentLayer);
|
||||
appointmentLayer++;
|
||||
}
|
||||
} else if (topAppointmentManager
|
||||
.multidayAppointmentsOverLimitOn(dayOfWeek) > 0) {
|
||||
layOnNMoreLabel(topAppointmentManager
|
||||
.multidayAppointmentsOverLimitOn(dayOfWeek),
|
||||
dayOfWeek, weekOfMonth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void layOnNMoreLabel(int moreCount, int dayOfWeek, int weekOfMonth) {
|
||||
Label more = new Label(CalendarFormat.MESSAGES.more(moreCount));
|
||||
more.setStyleName(MORE_LABEL_STYLE);
|
||||
placeItemInGrid(more, dayOfWeek, dayOfWeek, weekOfMonth,
|
||||
calculatedCellAppointments);
|
||||
appointmentCanvas.add(more);
|
||||
moreLabels.put(more.getElement(), (dayOfWeek) + (weekOfMonth * 7));
|
||||
}
|
||||
|
||||
private void layOnAppointment(Appointment appointment, int colStart,
|
||||
int colEnd, int row, int cellPosition) {
|
||||
AppointmentWidget panel = new AppointmentWidget(appointment);
|
||||
|
||||
placeItemInGrid(panel, colStart, colEnd, row, cellPosition);
|
||||
|
||||
boolean selected = calendarWidget.isTheSelectedAppointment(appointment);
|
||||
styleManager.applyStyle(panel, selected);
|
||||
|
||||
if(calendarWidget.getSettings().isEnableDragDrop() && !appointment.isReadOnly())
|
||||
dragController.makeDraggable(panel);
|
||||
|
||||
if(selected)
|
||||
selectedAppointmentWidgets.add(panel);
|
||||
|
||||
appointmentsWidgets.add(panel);
|
||||
appointmentCanvas.add(panel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Month View's primary style name.
|
||||
*/
|
||||
public String getStyleName() {
|
||||
return MONTH_VIEW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the DoubleClick event to determine if an Appointment has been
|
||||
* selected. If an appointment has been double clicked the OpenEvent will
|
||||
* get fired for that appointment.
|
||||
*/
|
||||
public void onDoubleClick(Element clickedElement, Event event) {
|
||||
if (clickedElement.equals(appointmentCanvas.getElement())) {
|
||||
if (calendarWidget.getSettings().getTimeBlockClickNumber() == Click.Double) {
|
||||
dayClicked(event);
|
||||
}
|
||||
} else {
|
||||
ArrayList<AppointmentWidget> list = findAppointmentWidgetsByElement(clickedElement);
|
||||
if (!list.isEmpty()) {
|
||||
calendarWidget.fireOpenEvent(list.get(0).getAppointment());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the a single click to determine if an appointment has been
|
||||
* selected. If an appointment is clicked it's selected status will be set
|
||||
* to true and a SelectionEvent will be fired.
|
||||
*/
|
||||
@Override
|
||||
public void onSingleClick(Element clickedElement, Event event) {
|
||||
if (clickedElement.equals(appointmentCanvas.getElement())) {
|
||||
if (calendarWidget.getSettings().getTimeBlockClickNumber() == Click.Single) {
|
||||
dayClicked(event);
|
||||
}
|
||||
} else {
|
||||
Appointment appointment = findAppointmentByElement(clickedElement);
|
||||
if (appointment != null) {
|
||||
selectAppointment(appointment);
|
||||
} else {
|
||||
// else, lets see if a "+ n more" label was clicked
|
||||
if (moreLabels.containsKey(clickedElement)) {
|
||||
calendarWidget.fireDateRequestEvent(
|
||||
cellDate(moreLabels.get(clickedElement)),
|
||||
clickedElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onMouseOver(Element element, Event event) {
|
||||
Appointment appointment = findAppointmentByElement(element);
|
||||
calendarWidget.fireMouseOverEvent(appointment, element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date corresponding to the <code>cell</code> (as if the
|
||||
* month view grid was a big linear sequence of cells) in the month view
|
||||
* grid.
|
||||
* @param cell The cell number in the month view grid
|
||||
* @return The date that corresponds to the given <code>cell</code>
|
||||
*/
|
||||
private Date cellDate(int cell) {
|
||||
return DateUtils.shiftDate(firstDateDisplayed, cell);
|
||||
}
|
||||
|
||||
private void dayClicked(Event event) {
|
||||
int y = event.getClientY() + Window.getScrollTop() - DOM.getAbsoluteTop(appointmentCanvas.getElement());
|
||||
int x = event.getClientX() + Window.getScrollLeft() - DOM.getAbsoluteLeft(appointmentCanvas.getElement());
|
||||
|
||||
int row = (int) Math.floor(y / (appointmentCanvas.getOffsetHeight() / monthViewRequiredRows));
|
||||
int col = (int) Math.floor(x / (appointmentCanvas.getOffsetWidth() / DAYS_IN_A_WEEK));
|
||||
calendarWidget.fireTimeBlockClickEvent(
|
||||
cellDate(row * DAYS_IN_A_WEEK + col));
|
||||
}
|
||||
|
||||
private ArrayList<AppointmentWidget> findAppointmentWidgetsByElement(
|
||||
Element element) {
|
||||
return findAppointmentWidgets(findAppointmentByElement(element));
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and formats the Calendar Grid. No appointments are included when
|
||||
* building the grid.
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private void buildCalendarGrid() {
|
||||
int firstDayOfWeek = CalendarFormat.INSTANCE.getFirstDayOfWeek();
|
||||
int month = calendarWidget.getDate().getMonth();
|
||||
firstDateDisplayed = firstDateShownInAMonthView(
|
||||
calendarWidget.getDate(), firstDayOfWeek);
|
||||
|
||||
Date today = new Date();
|
||||
DateUtils.resetTime(today);
|
||||
|
||||
/* Add the calendar weekday heading */
|
||||
for (int i = 0; i < DAYS_IN_A_WEEK; i++) {
|
||||
monthCalendarGrid
|
||||
.setText(
|
||||
0,
|
||||
i,
|
||||
CalendarFormat.INSTANCE
|
||||
.getDayOfWeekAbbreviatedNames()[(i + firstDayOfWeek) % 7]);
|
||||
monthCalendarGrid.getCellFormatter().setVerticalAlignment(0, i,
|
||||
HasVerticalAlignment.ALIGN_TOP);
|
||||
monthCalendarGrid.getCellFormatter().setStyleName(0, i,
|
||||
WEEKDAY_LABEL_STYLE);
|
||||
}
|
||||
Date date = (Date)firstDateDisplayed.clone();
|
||||
monthViewRequiredRows = MonthViewDateUtils.monthViewRequiredRows(
|
||||
calendarWidget.getDate(), firstDayOfWeek);
|
||||
int weekNumber = DateUtils.calendarWeekIso(date);
|
||||
|
||||
for (int monthGridRowIndex = 1; monthGridRowIndex <= monthViewRequiredRows; monthGridRowIndex++) {
|
||||
for (int dayOfWeekIndex = 0; dayOfWeekIndex < DAYS_IN_A_WEEK; dayOfWeekIndex++) {
|
||||
|
||||
if (monthGridRowIndex != 1 || dayOfWeekIndex != 0) {
|
||||
moveOneDayForward(date);
|
||||
weekNumber = DateUtils.calendarWeekIso(date);
|
||||
}
|
||||
|
||||
configureDayInGrid(monthGridRowIndex, dayOfWeekIndex,
|
||||
date, date.equals(today),
|
||||
date.getMonth() != month, weekNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures a single day in the month grid of this <code>MonthView</code>.
|
||||
*
|
||||
* @param row
|
||||
* The row in the grid on which the day will be set
|
||||
* @param col
|
||||
* The col in the grid on which the day will be set
|
||||
* @param date
|
||||
* The Date in the grid
|
||||
* @param isToday
|
||||
* Indicates whether the day corresponds to today in the month
|
||||
* view
|
||||
* @param notInCurrentMonth
|
||||
* Indicates whether the day is in the current visualized month
|
||||
* or belongs to any of the two adjacent months of the current
|
||||
* month
|
||||
* @param weekNumber
|
||||
* The weekNumber to show in the cell, only appears in the first col.
|
||||
*/
|
||||
private void configureDayInGrid(int row, int col, Date date,
|
||||
boolean isToday, boolean notInCurrentMonth, int weekNumber) {
|
||||
HorizontalPanel panel = new HorizontalPanel();
|
||||
String text = String.valueOf(date.getDate());
|
||||
Label label = new Label(text);
|
||||
|
||||
StringBuilder headerStyle = new StringBuilder(CELL_HEADER_STYLE);
|
||||
StringBuilder cellStyle = new StringBuilder(CELL_STYLE);
|
||||
boolean found = false;
|
||||
|
||||
for (Date day : getSettings().getHolidays()) {
|
||||
if (DateUtils.areOnTheSameDay(day, date)) {
|
||||
headerStyle.append("-holiday");
|
||||
cellStyle.append("-holiday");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isToday) {
|
||||
headerStyle.append("-today");
|
||||
cellStyle.append("-today");
|
||||
} else if(!found && DateUtils.isWeekend(date)) {
|
||||
headerStyle.append("-weekend");
|
||||
cellStyle.append("-weekend");
|
||||
}
|
||||
|
||||
if (notInCurrentMonth) {
|
||||
headerStyle.append("-disabled");
|
||||
}
|
||||
|
||||
label.setStyleName(headerStyle.toString());
|
||||
addDayClickHandler(label, (Date)date.clone());
|
||||
|
||||
if (col == 0 && getSettings().isShowingWeekNumbers()) {
|
||||
Label weekLabel = new Label(String.valueOf(weekNumber));
|
||||
weekLabel.setStyleName(WEEKNUMBER_LABEL_STYLE);
|
||||
|
||||
panel.add(weekLabel);
|
||||
panel.setCellWidth(weekLabel, "25px");
|
||||
DOM.setStyleAttribute(label.getElement(), "paddingLeft", "5px");
|
||||
addWeekClickHandler(weekLabel, (Date)date.clone());
|
||||
}
|
||||
panel.add(label);
|
||||
|
||||
appointmentCanvas.add(panel);
|
||||
dayLabels.add(label);
|
||||
dayPanels.add(panel);
|
||||
|
||||
//monthCalendarGrid.setWidget(row, col, panel);
|
||||
monthCalendarGrid.getCellFormatter().setVerticalAlignment(row, col,
|
||||
HasVerticalAlignment.ALIGN_TOP);
|
||||
monthCalendarGrid.getCellFormatter().setStyleName(row, col,
|
||||
cellStyle.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Appointment} indirectly associated to the passed
|
||||
* <code>element</code>. Each Appointment drawn on the CalendarView maps to
|
||||
* a Widget and therefore an Element. This method attempts to find an
|
||||
* Appointment based on the provided Element. If no match is found a null
|
||||
* value is returned.
|
||||
*
|
||||
* @param element Element to look up.
|
||||
* @return Appointment matching the element.
|
||||
*/
|
||||
private Appointment findAppointmentByElement(Element element) {
|
||||
Appointment appointmentAtElement = null;
|
||||
for (AppointmentWidget widget : appointmentsWidgets) {
|
||||
if (DOM.isOrHasChild(widget.getElement(), element)) {
|
||||
appointmentAtElement = widget.getAppointment();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return appointmentAtElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds any related <code>AppointmentWidgets</code> associated to the
|
||||
* passed Appointment, <code>appt</code>.
|
||||
*
|
||||
* @param appt
|
||||
* Appointment to match.
|
||||
* @return List of related AppointmentWidget objects.
|
||||
*/
|
||||
private ArrayList<AppointmentWidget> findAppointmentWidgets(Appointment appt) {
|
||||
ArrayList<AppointmentWidget> appointmentWidgets = new ArrayList<AppointmentWidget>();
|
||||
if (appt != null) {
|
||||
for (AppointmentWidget widget : appointmentsWidgets) {
|
||||
if (widget.getAppointment().equals(appt)) {
|
||||
appointmentWidgets.add(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
return appointmentWidgets;
|
||||
}
|
||||
|
||||
public void onDeleteKeyPressed() {
|
||||
if (calendarWidget.getSelectedAppointment() != null)
|
||||
calendarWidget.fireDeleteEvent(calendarWidget
|
||||
.getSelectedAppointment());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppointmentSelected(Appointment appt) {
|
||||
ArrayList<AppointmentWidget> clickedAppointmentWidgets = findAppointmentWidgets(appt);
|
||||
|
||||
if (!clickedAppointmentWidgets.isEmpty()) {
|
||||
for (AppointmentWidget widget : selectedAppointmentWidgets) {
|
||||
//widget.removeStyleDependentName("selected");
|
||||
//DOM.setStyleAttribute(widget.getElement(),
|
||||
// "borderColor", widget.getAppointment().getAppointmentStyle().getBorder());
|
||||
styleManager.applyStyle(widget, false);
|
||||
}
|
||||
|
||||
for (AppointmentWidget widget : clickedAppointmentWidgets) {
|
||||
//widget.addStyleDependentName("selected");
|
||||
//DOM.setStyleAttribute(widget.getElement(),
|
||||
// "borderColor", appt.getAppointmentStyle().getSelectedBorder());
|
||||
styleManager.applyStyle(widget, true);
|
||||
}
|
||||
|
||||
selectedAppointmentWidgets.clear();
|
||||
selectedAppointmentWidgets = clickedAppointmentWidgets;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiple calculated ("cached") values reused during
|
||||
* laying out the month view elements.
|
||||
*/
|
||||
|
||||
private int calculatedWeekDayHeaderHeight;
|
||||
private int calculatedDayHeaderHeight;
|
||||
|
||||
/**
|
||||
* Maximum appointments per cell (day).
|
||||
*/
|
||||
private int calculatedCellAppointments;
|
||||
|
||||
/**
|
||||
* Height of each Cell (day), including the day's header.
|
||||
*/
|
||||
private float calculatedCellOffsetHeight;
|
||||
|
||||
/**
|
||||
* Height of each Cell (day), excluding the day's header.
|
||||
*/
|
||||
private float calculatedCellHeight;
|
||||
|
||||
/**
|
||||
* Calculates the height of each day cell in the Month grid. It excludes the
|
||||
* height of each day's header, as well as the overall header that shows the
|
||||
* weekday labels.
|
||||
*/
|
||||
private void calculateCellHeight() {
|
||||
|
||||
int gridHeight = monthCalendarGrid.getOffsetHeight();
|
||||
int weekdayRowHeight = monthCalendarGrid.getRowFormatter()
|
||||
.getElement(0).getOffsetHeight();
|
||||
int dayHeaderHeight = dayLabels.get(0).getOffsetHeight();
|
||||
|
||||
calculatedCellOffsetHeight = (float) (gridHeight - weekdayRowHeight)
|
||||
/ monthViewRequiredRows;
|
||||
calculatedCellHeight = calculatedCellOffsetHeight - dayHeaderHeight;
|
||||
calculatedWeekDayHeaderHeight = weekdayRowHeight;
|
||||
calculatedDayHeaderHeight = dayHeaderHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the maximum number of appointments that can be displayed in a
|
||||
* given "day cell".
|
||||
*/
|
||||
private void calculateCellAppointments() {
|
||||
int paddingTop = appointmentPaddingTop();
|
||||
int height = appointmentHeight();
|
||||
|
||||
calculatedCellAppointments = (int)
|
||||
Math.floor((float) (calculatedCellHeight - paddingTop)
|
||||
/ (float) (height + paddingTop)) - 1;
|
||||
}
|
||||
|
||||
private static int appointmentPaddingTop() {
|
||||
return 1 + (Math.abs(FormattingUtil.getBorderOffset()) * 3);
|
||||
}
|
||||
|
||||
private static int appointmentHeight() {
|
||||
// TODO: calculate appointment height dynamically
|
||||
return 20;
|
||||
}
|
||||
|
||||
private void placeItemInGrid(Widget panel, int colStart, int colEnd,
|
||||
int row, int cellPosition) {
|
||||
int paddingTop = appointmentPaddingTop() + 3;
|
||||
int height = appointmentHeight();
|
||||
|
||||
float left = (float) colStart / (float) DAYS_IN_A_WEEK * 100f + .5f;
|
||||
|
||||
float width = ((float) (colEnd - colStart + 1) / (float) DAYS_IN_A_WEEK) * 100f - 1f;
|
||||
|
||||
float top = calculatedWeekDayHeaderHeight
|
||||
+ (row * calculatedCellOffsetHeight)
|
||||
+ calculatedDayHeaderHeight + paddingTop
|
||||
+ (cellPosition * (height + paddingTop));
|
||||
// System.out.println( "\t" + calculatedWeekDayHeaderHeight + " + (" + row +
|
||||
// " * " + calculatedCellOffsetHeight + ") + " +
|
||||
// calculatedDayHeaderHeight + " + " + paddingTop + " + (" +
|
||||
// cellPosition+"*("+height+"+"+paddingTop + "));");
|
||||
|
||||
DOM.setStyleAttribute(panel.getElement(), "position", "absolute");
|
||||
DOM.setStyleAttribute(panel.getElement(), "top", top + "px");
|
||||
DOM.setStyleAttribute(panel.getElement(), "left", left + "%");
|
||||
DOM.setStyleAttribute(panel.getElement(), "width", width + "%");
|
||||
}
|
||||
|
||||
private void placeDayLabelInGrid(Widget panel, int col, int row) {
|
||||
int paddingTop = appointmentPaddingTop();
|
||||
|
||||
float left = (float) col / (float) DAYS_IN_A_WEEK * 100f + .5f;
|
||||
|
||||
float width = (1f / (float) DAYS_IN_A_WEEK) * 100f - 1f;
|
||||
|
||||
float top = calculatedWeekDayHeaderHeight
|
||||
+ (row * calculatedCellOffsetHeight)
|
||||
+ paddingTop;
|
||||
DOM.setStyleAttribute(panel.getElement(), "position", "absolute");
|
||||
DOM.setStyleAttribute(panel.getElement(), "top", top + "px");
|
||||
DOM.setStyleAttribute(panel.getElement(), "left", left + "%");
|
||||
DOM.setStyleAttribute(panel.getElement(), "width", width + "%");
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
import static com.bradrydzewski.gwt.calendar.client.DateUtils.areOnTheSameMonth;
|
||||
import static com.bradrydzewski.gwt.calendar.client.DateUtils.firstOfNextMonth;
|
||||
import static com.bradrydzewski.gwt.calendar.client.DateUtils.previousDay;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
|
||||
/**
|
||||
* Contains date-related utilities with logic required to generate the {@link
|
||||
* com.bradrydzewski.gwt.calendar.client.monthview.MonthView}.
|
||||
*
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class MonthViewDateUtils {
|
||||
|
||||
/**
|
||||
* Calculates the first date that should be displayed in a month view.
|
||||
* Depending on the year and month, sometimes, viewing at a month will show
|
||||
* days from the previous month in the first week.
|
||||
*
|
||||
* @param dayInMonth Any day in the month that is being visualized in a
|
||||
* month view
|
||||
* @param firstDayOfWeek The day the weeks start on the month view, Sunday is
|
||||
* <code>0</code>, Monday is <code>1</code>, etc.
|
||||
* @return The first date that should appear on the first week of a month
|
||||
* view
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static Date firstDateShownInAMonthView(Date dayInMonth,
|
||||
int firstDayOfWeek) {
|
||||
Date date = DateUtils.firstOfTheMonth(dayInMonth);
|
||||
int firstDayOffset = firstDayOfWeek + date.getDate() - date.getDay();
|
||||
date.setDate(firstDayOffset);
|
||||
if (areOnTheSameMonth(date, dayInMonth) && date.getDate() > 1) {
|
||||
date.setDate(firstDayOffset - 7);
|
||||
}
|
||||
return date;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dynamically calculates the number of rows required to display all the days
|
||||
* in a month.
|
||||
*
|
||||
* @param dayInMonth Any day in the month that is being visualized through
|
||||
* the month view
|
||||
* @param firstDayOfWeek The day the weeks start on the month view, Sunday is
|
||||
* <code>0</code>, Monday is <code>1</code>, etc.
|
||||
* @return The number of rows (which represent weeks in the month view)
|
||||
* required to display all days in the month view
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static int monthViewRequiredRows(Date dayInMonth,
|
||||
int firstDayOfWeek) {
|
||||
int requiredRows = 5;
|
||||
|
||||
Date firstOfTheMonthClone = (Date) dayInMonth.clone();
|
||||
firstOfTheMonthClone.setDate(1);
|
||||
|
||||
Date firstDayInCalendar =
|
||||
firstDateShownInAMonthView(dayInMonth, firstDayOfWeek);
|
||||
|
||||
if (firstDayInCalendar.getMonth() != firstOfTheMonthClone.getMonth()) {
|
||||
Date lastDayOfPreviousMonth = previousDay(firstOfTheMonthClone);
|
||||
int prevMonthOverlap =
|
||||
daysInPeriod(firstDayInCalendar, lastDayOfPreviousMonth);
|
||||
|
||||
Date firstOfNextMonth = firstOfNextMonth(firstOfTheMonthClone);
|
||||
|
||||
int daysInMonth =
|
||||
daysInPeriod(firstOfTheMonthClone, previousDay(firstOfNextMonth));
|
||||
|
||||
if (prevMonthOverlap + daysInMonth > 35) {
|
||||
requiredRows = 6;
|
||||
}
|
||||
}
|
||||
return requiredRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total number of days between <code>start</code> and
|
||||
* <code>end</code>.
|
||||
*
|
||||
* @param start The first day in the period
|
||||
* @param end The last day in the period
|
||||
* @return The number of days between <code>start</code> and
|
||||
* <code>end</code>, the minimum difference being one
|
||||
* (<code>1</code>)
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private static int daysInPeriod(Date start, Date end) {
|
||||
if (start.getMonth() != end.getMonth()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Start and end dates must be in the same month.");
|
||||
}
|
||||
return 1 + end.getDate() - start.getDate();
|
||||
}
|
||||
}
|
@ -0,0 +1,123 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2011 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.ThemeAppointmentStyle;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
|
||||
/**
|
||||
* Applies styles in a month view based on the currently selected theme. This class
|
||||
* provides a template method to consistently style the appointments in a month view. Subclasses
|
||||
* provide appropriate appointment styles based on a specific theme using methods
|
||||
* {@link #getViewAppointmentStyleForTheme(com.bradrydzewski.gwt.calendar.client.Appointment)} and
|
||||
* {@link #getDefaultViewAppointmentStyleForTheme()}.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @author Carlos D. Morales
|
||||
* @see com.bradrydzewski.gwt.calendar.theme.google.client.GoogleMonthViewStyleManager
|
||||
* @see com.bradrydzewski.gwt.calendar.theme.ical.client.ICalMonthViewStyleManager
|
||||
*/
|
||||
public abstract class MonthViewStyleManager {
|
||||
|
||||
protected static final String APPOINTMENT_STYLE = "appointment";
|
||||
protected static final String APPOINTMENT_STYLE_SELECTED = "-selected";
|
||||
protected static final String APPOINTMENT_STYLE_MULTIDAY = "-multiday";
|
||||
|
||||
protected static final String BACKGROUND_COLOR_STYLE_ATTRIBUTE = "backgroundColor";
|
||||
protected static final String BORDER_COLOR_STYLE_ATTRIBUTE = "borderColor";
|
||||
protected static final String COLOR_STYLE_ATTRIBUTE = "color";
|
||||
|
||||
/**
|
||||
* Returns the appointment style appropriate to the passed appointment based on a specific theme.
|
||||
*
|
||||
* @param appointment An appointment to be displayed in the month view, should include a style to be used
|
||||
* @return The style to use with a theme, can be <code>null</code> if a default should be used
|
||||
* @see com.bradrydzewski.gwt.calendar.client.monthview.MonthViewStyleManager#getDefaultViewAppointmentStyleForTheme()
|
||||
*/
|
||||
protected abstract ThemeAppointmentStyle getViewAppointmentStyleForTheme(Appointment appointment);
|
||||
|
||||
/**
|
||||
* Returns the default appointment style corresponding to the currently used theme. Subclasses
|
||||
* should provide a style to be used if no appropriate style can be identified
|
||||
* ({@link #getViewAppointmentStyleForTheme(com.bradrydzewski.gwt.calendar.client.Appointment)} returns <code>null</code>).
|
||||
*
|
||||
* @return The style to use with a theme if no specific style can be identified with
|
||||
* {@link #getViewAppointmentStyleForTheme(com.bradrydzewski.gwt.calendar.client.Appointment)}
|
||||
*/
|
||||
protected abstract ThemeAppointmentStyle getDefaultViewAppointmentStyleForTheme();
|
||||
|
||||
/**
|
||||
* Applies a style in the currently selected theme using the runtime-provided
|
||||
* theme styles defined by {@link #getViewAppointmentStyleForTheme(com.bradrydzewski.gwt.calendar.client.Appointment)}
|
||||
* and {@link #getDefaultViewAppointmentStyleForTheme()}.
|
||||
*
|
||||
* @param widget The widget to style
|
||||
* @param selected Indicates if the appointment is the currently selected in the view
|
||||
*/
|
||||
public void applyStyle(AppointmentWidget widget, boolean selected) {
|
||||
doApplyStyleInternal(widget, selected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Template method to consistently apply the styles to an appointment in the month view.
|
||||
*
|
||||
* @param widget The widget to style
|
||||
* @param selected Indicates if the appointment is the currently selected in the view
|
||||
*/
|
||||
protected void doApplyStyleInternal(AppointmentWidget widget, boolean selected) {
|
||||
//Extract the Appointment for later reference
|
||||
Appointment appointment = widget.getAppointment();
|
||||
//Extract the DOM Element for later reference
|
||||
Element elem = widget.getElement();
|
||||
//Is MultiDay?
|
||||
boolean multiDay = appointment.isMultiDay() || appointment.isAllDay();
|
||||
|
||||
//Lookup the style from the map
|
||||
ThemeAppointmentStyle style = getViewAppointmentStyleForTheme(appointment);
|
||||
|
||||
//Determine Style Name
|
||||
String styleName = APPOINTMENT_STYLE;
|
||||
if (multiDay) styleName += APPOINTMENT_STYLE_MULTIDAY;
|
||||
if (selected) styleName += APPOINTMENT_STYLE_SELECTED;
|
||||
widget.setStylePrimaryName(styleName);
|
||||
|
||||
//If no style is found, apply the default blue style
|
||||
//TODO: need to check for a custom style
|
||||
if (style == null)
|
||||
style = getDefaultViewAppointmentStyleForTheme();
|
||||
|
||||
//Apply Single vs. Multi-day style
|
||||
if (multiDay) {
|
||||
|
||||
DOM.setStyleAttribute(elem, BACKGROUND_COLOR_STYLE_ATTRIBUTE, style.getBackground());
|
||||
DOM.setStyleAttribute(elem, BORDER_COLOR_STYLE_ATTRIBUTE, style.getBorder());
|
||||
|
||||
} else {
|
||||
|
||||
DOM.setStyleAttribute(elem, COLOR_STYLE_ATTRIBUTE, style.getSelectedBorder());
|
||||
}
|
||||
|
||||
//Apply style specific to selected appointments
|
||||
if (selected) {
|
||||
|
||||
DOM.setStyleAttribute(elem, BORDER_COLOR_STYLE_ATTRIBUTE, style.getSelectedBorder());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.monthview;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
|
||||
/**
|
||||
* Describes the layout of days (single, all and multi-day) within a single week
|
||||
* that is visualized in the <code>MonthView</code>. A <code>WeekLayoutDescription</code>
|
||||
* is not aware of any other thing than placing an appointment
|
||||
* <em>horizontally</em>, i.e., without considering the exact week the
|
||||
* appointment belongs to. It is the <code>MonthLayoutDescription</code>
|
||||
* responsibility to allocate the month necessary <code>weeks</code> and
|
||||
* distributing appointments over them.
|
||||
*
|
||||
* @author Carlos D. Morales
|
||||
* @see com.bradrydzewski.gwt.calendar.client.monthview.MonthView
|
||||
* @see com.bradrydzewski.gwt.calendar.client.monthview.MonthLayoutDescription
|
||||
*/
|
||||
public class WeekLayoutDescription {
|
||||
|
||||
public static final int FIRST_DAY = 0;
|
||||
public static final int LAST_DAY = 6;
|
||||
private AppointmentStackingManager topAppointmentsManager = null;
|
||||
|
||||
private DayLayoutDescription[] days = null;
|
||||
|
||||
private Date calendarFirstDay = null;
|
||||
private Date calendarLastDay = null;
|
||||
|
||||
private int maxLayer = -1;
|
||||
|
||||
public WeekLayoutDescription(Date calendarFirstDay, Date calendarLastDay,
|
||||
int maxLayer) {
|
||||
this.calendarFirstDay = calendarFirstDay;
|
||||
this.calendarLastDay = calendarLastDay;
|
||||
days = new DayLayoutDescription[7];
|
||||
this.maxLayer = maxLayer;
|
||||
topAppointmentsManager = new AppointmentStackingManager();
|
||||
topAppointmentsManager.setLayerOverflowLimit(this.maxLayer);
|
||||
}
|
||||
|
||||
public WeekLayoutDescription(Date calendarFirstDay, Date calendarLastDay) {
|
||||
this(calendarFirstDay, calendarLastDay, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
private void assertValidDayIndex(int day) {
|
||||
if (day < FIRST_DAY || day > days.length) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid day index (" + day + ")");
|
||||
}
|
||||
}
|
||||
|
||||
private DayLayoutDescription initDay(int day) {
|
||||
assertValidDayIndex(day);
|
||||
if (days[day] == null) {
|
||||
days[day] = new DayLayoutDescription(day);
|
||||
}
|
||||
return days[day];
|
||||
}
|
||||
|
||||
public boolean areThereAppointmentsOnDay(int day) {
|
||||
assertValidDayIndex(day);
|
||||
return days[day] != null
|
||||
|| topAppointmentsManager.areThereAppointmentsOn(day);
|
||||
}
|
||||
|
||||
public DayLayoutDescription getDayLayoutDescription(int day) {
|
||||
assertValidDayIndex(day);
|
||||
if (!areThereAppointmentsOnDay(day)) {
|
||||
return null;
|
||||
}
|
||||
return days[day];
|
||||
}
|
||||
|
||||
public void addAppointment(Appointment appointment) {
|
||||
int dayOfWeek = dayInWeek(appointment.getStart());
|
||||
if (appointment.isAllDay()) {
|
||||
topAppointmentsManager.assignLayer(
|
||||
new AppointmentLayoutDescription(dayOfWeek, appointment));
|
||||
} else {
|
||||
initDay(dayOfWeek).addAppointment(appointment);
|
||||
}
|
||||
}
|
||||
|
||||
public int currentStackOrderInDay(int dayIndex) {
|
||||
return topAppointmentsManager.lowestLayerIndex(dayIndex);
|
||||
}
|
||||
|
||||
public void addMultiDayAppointment(Appointment appointment) {
|
||||
int weekStartDay = dayInWeek(appointment.getStart());
|
||||
int weekEndDay = dayInWeek(appointment.getEnd());
|
||||
|
||||
if(!appointment.getEnd().before(calendarLastDay)) {
|
||||
weekEndDay = LAST_DAY;
|
||||
}
|
||||
|
||||
topAppointmentsManager.assignLayer(
|
||||
new AppointmentLayoutDescription(weekStartDay, weekEndDay,
|
||||
appointment));
|
||||
}
|
||||
|
||||
public void addMultiWeekAppointment(Appointment appointment,
|
||||
AppointmentWidgetParts presenceInMonth) {
|
||||
|
||||
switch (presenceInMonth) {
|
||||
case FIRST_WEEK:
|
||||
int weekStartDay = dayInWeek(appointment.getStart());
|
||||
topAppointmentsManager.assignLayer(
|
||||
new AppointmentLayoutDescription(weekStartDay, LAST_DAY,
|
||||
appointment));
|
||||
break;
|
||||
case IN_BETWEEN:
|
||||
topAppointmentsManager.assignLayer(
|
||||
new AppointmentLayoutDescription(FIRST_DAY, LAST_DAY, appointment));
|
||||
break;
|
||||
case LAST_WEEK:
|
||||
int weekEndDay = dayInWeek(appointment.getEnd());
|
||||
topAppointmentsManager.assignLayer(
|
||||
new AppointmentLayoutDescription(FIRST_DAY, weekEndDay,
|
||||
appointment));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private int dayInWeek(Date date) {
|
||||
if (date.before(calendarFirstDay)) {
|
||||
return FIRST_DAY;
|
||||
}
|
||||
|
||||
if (date.after(calendarLastDay)) {
|
||||
return LAST_DAY;
|
||||
}
|
||||
|
||||
return (int) Math
|
||||
.floor(DateUtils.differenceInDays(date, calendarFirstDay) % 7d);
|
||||
}
|
||||
|
||||
public AppointmentStackingManager getTopAppointmentsManager() {
|
||||
return topAppointmentsManager;
|
||||
}
|
||||
}
|
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import static com.bradrydzewski.gwt.calendar.client.DateUtils.minutesSinceDayStarted;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
|
||||
/**
|
||||
* The Appointment Adapter is used to track the layout of an
|
||||
* {@link Appointment}. It adds additional fields required to
|
||||
* calculate layout that are used by the Layout Strategy classes.
|
||||
*
|
||||
* This adapter allows us to keep these fields outside of the
|
||||
* {@link Appointment} class and keep the layout computations' complexity
|
||||
* away from the user.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class AppointmentAdapter {
|
||||
|
||||
private Appointment appointment;
|
||||
private int cellStart;
|
||||
private int cellSpan;
|
||||
private int columnStart = -1;
|
||||
private int columnSpan;
|
||||
private int appointmentStart;
|
||||
private int appointmentEnd;
|
||||
private float cellPercentFill;
|
||||
private float cellPercentStart;
|
||||
private List<TimeBlock> intersectingBlocks;
|
||||
private float top;
|
||||
private float left;
|
||||
private float width;
|
||||
private float height;
|
||||
|
||||
public float getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public void setTop(float top) {
|
||||
this.top = top;
|
||||
}
|
||||
|
||||
public float getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public void setLeft(float left) {
|
||||
this.left = left;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(float width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(float height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public AppointmentAdapter(Appointment appointment) {
|
||||
this.appointment = appointment;
|
||||
this.appointmentStart = minutesSinceDayStarted(appointment.getStart());
|
||||
this.appointmentEnd = minutesSinceDayStarted(appointment.getEnd());
|
||||
this.intersectingBlocks = new ArrayList<TimeBlock>();
|
||||
}
|
||||
|
||||
public int getCellStart() {
|
||||
return cellStart;
|
||||
}
|
||||
|
||||
public void setCellStart(int cellStart) {
|
||||
this.cellStart = cellStart;
|
||||
}
|
||||
|
||||
public int getCellSpan() {
|
||||
return cellSpan;
|
||||
}
|
||||
|
||||
public void setCellSpan(int cellSpan) {
|
||||
this.cellSpan = cellSpan;
|
||||
}
|
||||
|
||||
public int getColumnStart() {
|
||||
return columnStart;
|
||||
}
|
||||
|
||||
public void setColumnStart(int columnStart) {
|
||||
this.columnStart = columnStart;
|
||||
}
|
||||
|
||||
public int getColumnSpan() {
|
||||
return columnSpan;
|
||||
}
|
||||
|
||||
public void setColumnSpan(int columnSpan) {
|
||||
this.columnSpan = columnSpan;
|
||||
}
|
||||
|
||||
public int getAppointmentStart() {
|
||||
return appointmentStart;
|
||||
}
|
||||
|
||||
public void setAppointmentStart(int appointmentStart) {
|
||||
this.appointmentStart = appointmentStart;
|
||||
}
|
||||
|
||||
public int getAppointmentEnd() {
|
||||
return appointmentEnd;
|
||||
}
|
||||
|
||||
public void setAppointmentEnd(int appointmentEnd) {
|
||||
this.appointmentEnd = appointmentEnd;
|
||||
}
|
||||
|
||||
public List<TimeBlock> getIntersectingBlocks() {
|
||||
return intersectingBlocks;
|
||||
}
|
||||
|
||||
public void setIntersectingBlocks(List<TimeBlock> intersectingBlocks) {
|
||||
this.intersectingBlocks = intersectingBlocks;
|
||||
}
|
||||
|
||||
public Appointment getAppointment() {
|
||||
return appointment;
|
||||
}
|
||||
|
||||
public float getCellPercentFill() {
|
||||
return cellPercentFill;
|
||||
}
|
||||
|
||||
public void setCellPercentFill(float cellPercentFill) {
|
||||
this.cellPercentFill = cellPercentFill;
|
||||
}
|
||||
|
||||
public float getCellPercentStart() {
|
||||
return cellPercentStart;
|
||||
}
|
||||
|
||||
public void setCellPercentStart(float cellPercentStart) {
|
||||
this.cellPercentStart = cellPercentStart;
|
||||
}
|
||||
}
|
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.google.gwt.event.dom.client.HasAllMouseHandlers;
|
||||
import com.google.gwt.event.dom.client.MouseDownEvent;
|
||||
import com.google.gwt.event.dom.client.MouseDownHandler;
|
||||
import com.google.gwt.event.dom.client.MouseMoveEvent;
|
||||
import com.google.gwt.event.dom.client.MouseMoveHandler;
|
||||
import com.google.gwt.event.dom.client.MouseOutEvent;
|
||||
import com.google.gwt.event.dom.client.MouseOutHandler;
|
||||
import com.google.gwt.event.dom.client.MouseOverEvent;
|
||||
import com.google.gwt.event.dom.client.MouseOverHandler;
|
||||
import com.google.gwt.event.dom.client.MouseUpEvent;
|
||||
import com.google.gwt.event.dom.client.MouseUpHandler;
|
||||
import com.google.gwt.event.dom.client.MouseWheelEvent;
|
||||
import com.google.gwt.event.dom.client.MouseWheelHandler;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.ComplexPanel;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Panel;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public class AppointmentWidget extends FlowPanel {
|
||||
|
||||
class Div extends ComplexPanel implements HasAllMouseHandlers {
|
||||
|
||||
public Div() {
|
||||
setElement(DOM.createDiv());
|
||||
}
|
||||
|
||||
public void add(Widget w) {
|
||||
super.add(w, getElement());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseDownHandler(MouseDownHandler handler) {
|
||||
return addDomHandler(handler, MouseDownEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseUpHandler(MouseUpHandler handler) {
|
||||
return addDomHandler(handler, MouseUpEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) {
|
||||
return addDomHandler(handler, MouseOutEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) {
|
||||
return addDomHandler(handler, MouseOverEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseMoveHandler(MouseMoveHandler handler) {
|
||||
return addDomHandler(handler, MouseMoveEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addMouseWheelHandler(
|
||||
MouseWheelHandler handler) {
|
||||
return addDomHandler(handler, MouseWheelEvent.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private String title;
|
||||
private String description;
|
||||
private Date start;
|
||||
private Date end;
|
||||
private boolean selected;
|
||||
private float top;
|
||||
private float left;
|
||||
private float width;
|
||||
private float height;
|
||||
private Widget headerPanel = new Div();
|
||||
private Panel bodyPanel = new SimplePanel();
|
||||
private Widget footerPanel = new Div();
|
||||
private Panel timelinePanel = new SimplePanel();
|
||||
private Panel timelineFillPanel = new SimplePanel();
|
||||
private boolean multiDay = false;
|
||||
private Appointment appointment;
|
||||
|
||||
public AppointmentWidget() {
|
||||
this.setStylePrimaryName("gwt-appointment");
|
||||
headerPanel.setStylePrimaryName("header");
|
||||
bodyPanel.setStylePrimaryName("body");
|
||||
footerPanel.setStylePrimaryName("footer");
|
||||
timelinePanel.setStylePrimaryName("timeline");
|
||||
timelineFillPanel.setStylePrimaryName("timeline-fill");
|
||||
|
||||
this.add(headerPanel);
|
||||
this.add(bodyPanel);
|
||||
this.add(footerPanel);
|
||||
this.add(timelinePanel);
|
||||
timelinePanel.add(timelineFillPanel);
|
||||
DOM.setStyleAttribute(this.getElement(), "position", "absolute");
|
||||
}
|
||||
|
||||
public Widget getBody() {
|
||||
return this.bodyPanel;
|
||||
}
|
||||
|
||||
public Widget getHeader() {
|
||||
return this.headerPanel;
|
||||
}
|
||||
|
||||
public Date getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(Date start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public Date getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(Date end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public boolean isSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public float getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public void setTop(float top) {
|
||||
this.top = top;
|
||||
DOM.setStyleAttribute(this.getElement(), "top", top + "px");
|
||||
}
|
||||
|
||||
public float getLeft() {
|
||||
return left;
|
||||
}
|
||||
|
||||
public void setLeft(float left) {
|
||||
this.left = left;
|
||||
DOM.setStyleAttribute(this.getElement(), "left", left + "%");
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(float width) {
|
||||
this.width = width;
|
||||
DOM.setStyleAttribute(this.getElement(), "width", width + "%");
|
||||
}
|
||||
|
||||
public float getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(float height) {
|
||||
this.height = height;
|
||||
DOM.setStyleAttribute(this.getElement(), "height", height + "px");
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
DOM.setInnerHTML(headerPanel.getElement(), title);
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
DOM.setInnerHTML(bodyPanel.getElement(), description);
|
||||
}
|
||||
|
||||
public void formatTimeline(float top, float height) {
|
||||
timelineFillPanel.setHeight(height + "%");
|
||||
DOM.setStyleAttribute(timelineFillPanel.getElement(), "top", top + "%");
|
||||
}
|
||||
|
||||
public int compareTo(AppointmentWidget appt) {
|
||||
// -1 0 1
|
||||
// less, equal, greater
|
||||
int compare = this.getStart().compareTo(appt.getStart());
|
||||
|
||||
if (compare == 0) {
|
||||
compare = appt.getEnd().compareTo(this.getEnd());
|
||||
}
|
||||
|
||||
return compare;
|
||||
}
|
||||
|
||||
public Widget getMoveHandle() {
|
||||
return headerPanel;
|
||||
}
|
||||
|
||||
public Widget getResizeHandle() {
|
||||
return footerPanel;
|
||||
}
|
||||
|
||||
public boolean isMultiDay() {
|
||||
return multiDay;
|
||||
}
|
||||
|
||||
public void setMultiDay(boolean isMultiDay) {
|
||||
this.multiDay = isMultiDay;
|
||||
}
|
||||
|
||||
public Appointment getAppointment() {
|
||||
return appointment;
|
||||
}
|
||||
|
||||
public void setAppointment(Appointment appointment) {
|
||||
this.appointment = appointment;
|
||||
|
||||
if (appointment.isReadOnly()) {
|
||||
this.remove(footerPanel);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment;
|
||||
import com.google.gwt.user.client.ui.HasVerticalAlignment.VerticalAlignmentConstant;
|
||||
import com.google.gwt.user.client.ui.ScrollPanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
public class DayViewBody extends Composite {
|
||||
private FlexTable layout = new FlexTable();
|
||||
private ScrollPanel scrollPanel = new ScrollPanel();
|
||||
private DayViewTimeline timeline = null;
|
||||
private DayViewGrid grid = null;
|
||||
private HasSettings settings = null;
|
||||
|
||||
public void add(Widget w) {
|
||||
scrollPanel.add(w);
|
||||
}
|
||||
|
||||
public ScrollPanel getScrollPanel() {
|
||||
return scrollPanel;
|
||||
}
|
||||
|
||||
public DayViewGrid getGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public DayViewTimeline getTimeline() {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
public DayViewGrid getDayViewGrid() {
|
||||
return grid;
|
||||
}
|
||||
|
||||
public DayViewTimeline getDayViewTimeline() {
|
||||
return timeline;
|
||||
}
|
||||
|
||||
public DayViewBody(HasSettings settings) {
|
||||
initWidget(scrollPanel);
|
||||
this.settings = settings;
|
||||
this.timeline = new DayViewTimeline(settings);
|
||||
this.grid = new DayViewGrid(settings);
|
||||
scrollPanel.setStylePrimaryName("scroll-area");
|
||||
DOM.setStyleAttribute(scrollPanel.getElement(), "overflowX",
|
||||
"hidden");
|
||||
DOM.setStyleAttribute(scrollPanel.getElement(), "overflowY",
|
||||
"scroll");
|
||||
|
||||
// create the calendar body layout table
|
||||
// calendarBodyLayoutTable.setStyleName("scroll-area");
|
||||
layout.setCellPadding(0);
|
||||
layout.setBorderWidth(0);
|
||||
layout.setCellSpacing(0);
|
||||
layout.getColumnFormatter().setWidth(1, "99%");
|
||||
// set vertical alignment
|
||||
VerticalAlignmentConstant valign = HasVerticalAlignment.ALIGN_TOP;
|
||||
layout.getCellFormatter().setVerticalAlignment(0, 0, valign);
|
||||
layout.getCellFormatter().setVerticalAlignment(0, 1, valign);
|
||||
|
||||
grid.setStyleName("gwt-appointment-panel");
|
||||
|
||||
//TODO: use CSS to set table layout
|
||||
layout.getCellFormatter().setWidth(0, 0, "50px");
|
||||
DOM.setStyleAttribute(layout.getElement(), "tableLayout", "fixed");
|
||||
|
||||
layout.setWidget(0, 0, timeline);
|
||||
layout.setWidget(0, 1, grid);
|
||||
scrollPanel.add(layout);
|
||||
|
||||
}
|
||||
|
||||
public void setDays(Date date, int days) {
|
||||
grid.build(settings.getSettings().getWorkingHourStart(),
|
||||
settings.getSettings().getWorkingHourEnd(), days);
|
||||
}
|
||||
}
|
@ -0,0 +1,105 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.FormattingUtil;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.ComplexPanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
import com.google.gwt.user.client.ui.Widget;
|
||||
|
||||
/**
|
||||
* The DayGrid draws the grid that displays days / time intervals in the
|
||||
* body of the calendar.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class DayViewGrid /*Impl*/ extends Composite {
|
||||
|
||||
class Div extends ComplexPanel {
|
||||
|
||||
public Div() {
|
||||
setElement(DOM.createDiv());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Widget w) {
|
||||
return super.remove(w);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void add(Widget w) {
|
||||
super.add(w, getElement());
|
||||
}
|
||||
}
|
||||
|
||||
protected AbsolutePanel grid = new AbsolutePanel();
|
||||
protected SimplePanel gridOverlay = new SimplePanel();
|
||||
|
||||
private HasSettings settings = null;
|
||||
|
||||
private static final int HOURS_PER_DAY = 24;
|
||||
|
||||
public DayViewGrid(HasSettings settings) { //was DayViewGridImpl
|
||||
initWidget(grid);
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public void build(int workingHourStart, int workingHourStop, int days) {
|
||||
|
||||
grid.clear();
|
||||
|
||||
int intervalsPerHour = settings.getSettings().getIntervalsPerHour(); //2; //30 minute intervals
|
||||
float intervalSize = settings.getSettings().getPixelsPerInterval();
|
||||
|
||||
this.setHeight((intervalsPerHour * (intervalSize) * 24) + "px");
|
||||
|
||||
float dayWidth = 100f / days;
|
||||
float dayLeft = 0f;
|
||||
|
||||
int dayStartsAt = settings.getSettings().getDayStartsAt();
|
||||
|
||||
for (int i = 0; i < HOURS_PER_DAY; i++) {
|
||||
boolean isWorkingHours = ((i + dayStartsAt) >= workingHourStart && (i + dayStartsAt) <= workingHourStop);
|
||||
//create major interval
|
||||
SimplePanel sp1 = new SimplePanel();
|
||||
sp1.setStyleName("major-time-interval");
|
||||
sp1.setHeight(intervalSize + FormattingUtil.getBorderOffset() + "px");
|
||||
|
||||
//if working hours set
|
||||
if (isWorkingHours) {
|
||||
sp1.addStyleName("working-hours");
|
||||
}
|
||||
|
||||
//add to body
|
||||
grid.add(sp1);
|
||||
|
||||
for (int x = 0; x < intervalsPerHour - 1; x++) {
|
||||
SimplePanel sp2 = new SimplePanel();
|
||||
sp2.setStyleName("minor-time-interval");
|
||||
|
||||
sp2.setHeight(intervalSize + FormattingUtil.getBorderOffset() + "px");
|
||||
if (isWorkingHours) {
|
||||
sp2.addStyleName("working-hours");
|
||||
}
|
||||
grid.add(sp2);
|
||||
}
|
||||
}
|
||||
|
||||
for (int day = 0; day < days; day++) {
|
||||
dayLeft = dayWidth * day;
|
||||
SimplePanel dayPanel = new SimplePanel();
|
||||
dayPanel.setStyleName("day-separator");
|
||||
grid.add(dayPanel);
|
||||
DOM.setStyleAttribute(dayPanel.getElement(), "left", dayLeft + "%");
|
||||
}
|
||||
|
||||
gridOverlay.setHeight("100%");
|
||||
gridOverlay.setWidth("100%");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "position", "absolute");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "left", "0px");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "top", "0px");
|
||||
grid.add(gridOverlay);
|
||||
}
|
||||
}
|
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarFormat;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DaySelectionEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DaySelectionHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasDaySelectionHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.HasWeekSelectionHandlers;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.WeekSelectionEvent;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.WeekSelectionHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.WindowUtils;
|
||||
import com.google.gwt.event.dom.client.ClickEvent;
|
||||
import com.google.gwt.event.dom.client.ClickHandler;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.i18n.client.DateTimeFormat;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.VerticalPanel;
|
||||
|
||||
public class DayViewHeader extends Composite implements HasWeekSelectionHandlers<Date>, HasDaySelectionHandlers<Date> {
|
||||
private FlexTable header = new FlexTable();
|
||||
private VerticalPanel timePanel = new VerticalPanel();
|
||||
private AbsolutePanel dayPanel = new AbsolutePanel();
|
||||
private AbsolutePanel weekPanel = new AbsolutePanel();
|
||||
private AbsolutePanel splitter = new AbsolutePanel();
|
||||
private static final String GWT_CALENDAR_HEADER_STYLE = "gwt-calendar-header";
|
||||
private static final String DAY_CELL_CONTAINER_STYLE = "day-cell-container";
|
||||
private static final String WEEK_CELL_CONTAINER_STYLE = "week-cell-container";
|
||||
private static final String YEAR_CELL_STYLE = "year-cell";
|
||||
private static final String SPLITTER_STYLE = "splitter";
|
||||
private final boolean showWeekNumbers;
|
||||
private final HasSettings settings;
|
||||
|
||||
public DayViewHeader(HasSettings settings) {
|
||||
initWidget(header);
|
||||
|
||||
this.settings = settings;
|
||||
|
||||
header.setStyleName(GWT_CALENDAR_HEADER_STYLE);
|
||||
dayPanel.setStyleName(DAY_CELL_CONTAINER_STYLE);
|
||||
weekPanel.setStyleName(WEEK_CELL_CONTAINER_STYLE);
|
||||
timePanel.setWidth("100%");
|
||||
|
||||
showWeekNumbers = settings.getSettings().isShowingWeekNumbers();
|
||||
|
||||
header.insertRow(0);
|
||||
header.insertRow(0);
|
||||
header.insertCell(0, 0);
|
||||
header.insertCell(0, 0);
|
||||
header.insertCell(0, 0);
|
||||
header.setWidget(0, 1, timePanel);
|
||||
header.getCellFormatter().setStyleName(0, 0, YEAR_CELL_STYLE);
|
||||
header.getCellFormatter().setWidth(0, 2,
|
||||
WindowUtils.getScrollBarWidth(true) + "px");
|
||||
|
||||
header.getFlexCellFormatter().setColSpan(1, 0, 3);
|
||||
header.setCellPadding(0);
|
||||
header.setBorderWidth(0);
|
||||
header.setCellSpacing(0);
|
||||
|
||||
if (showWeekNumbers) {
|
||||
timePanel.add(weekPanel);
|
||||
}
|
||||
timePanel.add(dayPanel);
|
||||
|
||||
splitter.setStylePrimaryName(SPLITTER_STYLE);
|
||||
header.setWidget(1, 0, splitter);
|
||||
}
|
||||
|
||||
public void setDays(Date date, int days) {
|
||||
|
||||
dayPanel.clear();
|
||||
weekPanel.clear();
|
||||
|
||||
float dayWidth = 100f / days;
|
||||
float dayLeft;
|
||||
int week = DateUtils.calendarWeekIso(date);
|
||||
int previousDayWeek = week;
|
||||
Date previousDate = date;
|
||||
float weekWidth = 0f;
|
||||
float weekLeft = 0f;
|
||||
|
||||
for (int i = 0; i < days; i++) {
|
||||
|
||||
// set the left position of the day splitter to
|
||||
// the width * incremented value
|
||||
dayLeft = dayWidth * i;
|
||||
|
||||
// increment the date by 1
|
||||
if (i > 0) {
|
||||
DateUtils.moveOneDayForward(date);
|
||||
} else {
|
||||
// initialize the week values
|
||||
weekLeft = dayLeft;
|
||||
weekWidth = dayWidth;
|
||||
}
|
||||
|
||||
String headerTitle = CalendarFormat.INSTANCE.getDateFormat().format(date);
|
||||
|
||||
Label dayLabel = new Label();
|
||||
dayLabel.setStylePrimaryName("day-cell");
|
||||
dayLabel.setWidth(dayWidth + "%");
|
||||
dayLabel.setText(headerTitle);
|
||||
DOM.setStyleAttribute(dayLabel.getElement(), "left", dayLeft + "%");
|
||||
|
||||
addDayClickHandler(dayLabel, (Date) date.clone());
|
||||
|
||||
boolean found = false;
|
||||
for (Date day : settings.getSettings().getHolidays()) {
|
||||
if (DateUtils.areOnTheSameDay(day, date)) {
|
||||
dayLabel.setStyleName("day-cell-holiday");
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// set the style of the header to show that it is today
|
||||
if (DateUtils.areOnTheSameDay(new Date(), date)) {
|
||||
dayLabel.setStyleName("day-cell-today");
|
||||
} else if (!found && DateUtils.isWeekend(date)) {
|
||||
dayLabel.setStyleName("day-cell-weekend");
|
||||
}
|
||||
|
||||
if (showWeekNumbers) {
|
||||
week = DateUtils.calendarWeekIso(date);
|
||||
boolean lastDay = i + 1 == days;
|
||||
if ((previousDayWeek != week) || lastDay) {
|
||||
if (lastDay) {
|
||||
previousDayWeek = week;
|
||||
previousDate = date;
|
||||
}
|
||||
String weekTitle = "W " + previousDayWeek;
|
||||
|
||||
Label weekLabel = new Label();
|
||||
weekLabel.setStylePrimaryName("week-cell");
|
||||
weekLabel.setWidth(weekWidth + "%");
|
||||
weekLabel.setText(weekTitle);
|
||||
DOM.setStyleAttribute(weekLabel.getElement(), "left", weekLeft + "%");
|
||||
|
||||
addWeekClickHandler(weekLabel, previousDate);
|
||||
|
||||
weekPanel.add(weekLabel);
|
||||
|
||||
weekWidth = dayWidth;
|
||||
weekLeft = dayLeft + dayWidth;
|
||||
} else {
|
||||
weekWidth += dayWidth;
|
||||
}
|
||||
previousDayWeek = week;
|
||||
previousDate = date;
|
||||
}
|
||||
|
||||
dayPanel.add(dayLabel);
|
||||
}
|
||||
}
|
||||
|
||||
public void setYear(Date date) {
|
||||
setYear(DateUtils.year(date));
|
||||
}
|
||||
|
||||
public void setYear(int year) {
|
||||
header.setText(0, 0, String.valueOf(year));
|
||||
}
|
||||
|
||||
public void setFuckingDayOfYear(Date date) {
|
||||
}
|
||||
|
||||
private void addDayClickHandler(final Label dayLabel, final Date day) {
|
||||
dayLabel.addClickHandler(new ClickHandler() {
|
||||
public void onClick(ClickEvent event) {
|
||||
fireSelectedDay(day);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addWeekClickHandler(final Label weekLabel, final Date day) {
|
||||
weekLabel.addClickHandler(new ClickHandler() {
|
||||
public void onClick(ClickEvent event) {
|
||||
fireSelectedWeek(day);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void fireSelectedDay(final Date day) {
|
||||
DaySelectionEvent.fire(this, day);
|
||||
}
|
||||
|
||||
private void fireSelectedWeek(final Date day) {
|
||||
WeekSelectionEvent.fire(this, day);
|
||||
}
|
||||
|
||||
public HandlerRegistration addWeekSelectionHandler(
|
||||
WeekSelectionHandler<Date> handler) {
|
||||
return addHandler(handler, WeekSelectionEvent.getType());
|
||||
}
|
||||
|
||||
public HandlerRegistration addDaySelectionHandler(
|
||||
DaySelectionHandler<Date> handler) {
|
||||
return addHandler(handler, DaySelectionEvent.getType());
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.WindowUtils;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlexTable;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
|
||||
/**
|
||||
* A widget to render multi-day appointments in a day view.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class DayViewMultiDayBody extends Composite {
|
||||
|
||||
private FlexTable header = new FlexTable();
|
||||
protected AbsolutePanel grid = new AbsolutePanel();
|
||||
private AbsolutePanel splitter = new AbsolutePanel();
|
||||
private static final String TIMELINE_EMPTY_CELL_STYLE = "leftEmptyCell";
|
||||
private static final String SCROLLBAR_EMPTY_CELL_STYLE = "rightEmptyCell";
|
||||
private static final String DAY_CONTAINER_CELL_STYLE = "centerDayContainerCell";
|
||||
private static final String SPLITTER_STYLE = "splitter";
|
||||
protected SimplePanel gridOverlay = new SimplePanel();
|
||||
|
||||
public DayViewMultiDayBody(HasSettings settings) {
|
||||
|
||||
initWidget(header);
|
||||
|
||||
this.header.setStyleName("multiDayBody");
|
||||
this.setWidth("100%");
|
||||
|
||||
/* insert two rows ... first row holds multi-day appointments,
|
||||
* second row is just a splitter */
|
||||
header.insertRow(0);
|
||||
header.insertRow(0);
|
||||
//insert 3 cells
|
||||
//1st cell is empty to align with the timeline
|
||||
//2nd cell holds appointments
|
||||
//3rd cell is empty, aligns with scrollbar
|
||||
header.insertCell(0, 0);
|
||||
header.insertCell(0, 0);
|
||||
header.insertCell(0, 0);
|
||||
|
||||
//add panel to hold appointments
|
||||
header.setWidget(0, 1, grid);
|
||||
|
||||
//set cell styles
|
||||
header.getCellFormatter().setStyleName(0, 0, TIMELINE_EMPTY_CELL_STYLE);
|
||||
header.getCellFormatter().setStyleName(0, 1, DAY_CONTAINER_CELL_STYLE);
|
||||
header.getCellFormatter().setStyleName(0, 2, SCROLLBAR_EMPTY_CELL_STYLE);
|
||||
header.getCellFormatter().setWidth(0, 2,
|
||||
WindowUtils.getScrollBarWidth(true) + "px");
|
||||
|
||||
//default grid to 50px height
|
||||
grid.setHeight("30px");
|
||||
|
||||
header.getFlexCellFormatter().setColSpan(1, 0, 3);
|
||||
header.setCellPadding(0);
|
||||
header.setBorderWidth(0);
|
||||
header.setCellSpacing(0);
|
||||
|
||||
splitter.setStylePrimaryName(SPLITTER_STYLE);
|
||||
header.setWidget(1, 0, splitter);
|
||||
}
|
||||
|
||||
public void setDays(Date date, int days) {
|
||||
|
||||
grid.clear();
|
||||
float dayWidth = 100f / days;
|
||||
float dayLeft;
|
||||
|
||||
for (int day = 0; day < days; day++) {
|
||||
dayLeft = dayWidth * day;
|
||||
SimplePanel dayPanel = new SimplePanel();
|
||||
dayPanel.setStyleName("day-separator");
|
||||
grid.add(dayPanel);
|
||||
DOM.setStyleAttribute(dayPanel.getElement(), "left", dayLeft + "%");
|
||||
}
|
||||
|
||||
gridOverlay.setHeight("100%");
|
||||
gridOverlay.setWidth("100%");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "position", "absolute");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "left", "0px");
|
||||
DOM.setStyleAttribute(gridOverlay.getElement(), "top", "0px");
|
||||
grid.add(gridOverlay);
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarFormat;
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.FormattingUtil;
|
||||
import com.google.gwt.user.client.ui.AbsolutePanel;
|
||||
import com.google.gwt.user.client.ui.Composite;
|
||||
import com.google.gwt.user.client.ui.FlowPanel;
|
||||
import com.google.gwt.user.client.ui.Label;
|
||||
import com.google.gwt.user.client.ui.SimplePanel;
|
||||
|
||||
/**
|
||||
* A sequential display of the hours in a day. Each
|
||||
* hour label should visually line up to a cell in the DayGrid.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class DayViewTimeline extends Composite {
|
||||
|
||||
private AbsolutePanel timelinePanel = new AbsolutePanel();
|
||||
private HasSettings settings = null;
|
||||
private static final String TIME_LABEL_STYLE = "hour-label";
|
||||
|
||||
public DayViewTimeline(HasSettings settings) {
|
||||
initWidget(timelinePanel);
|
||||
timelinePanel.setStylePrimaryName("time-strip");
|
||||
this.settings = settings;
|
||||
prepare();
|
||||
}
|
||||
|
||||
public final void prepare() {
|
||||
timelinePanel.clear();
|
||||
float labelHeight = settings.getSettings().getIntervalsPerHour()
|
||||
* settings.getSettings().getPixelsPerInterval();
|
||||
|
||||
int i = 0;
|
||||
if (settings.getSettings().isOffsetHourLabels()) {
|
||||
i = 1;
|
||||
SimplePanel sp = new SimplePanel();
|
||||
sp.setHeight((labelHeight / 2) + "px");
|
||||
timelinePanel.add(sp);
|
||||
}
|
||||
|
||||
int dayStartsAt = settings.getSettings().getDayStartsAt();
|
||||
|
||||
while (i < CalendarFormat.HOURS_IN_DAY) {
|
||||
int index = i + dayStartsAt;
|
||||
if (index >= CalendarFormat.HOURS_IN_DAY) {
|
||||
index = index - CalendarFormat.HOURS_IN_DAY;
|
||||
}
|
||||
String hour = CalendarFormat.INSTANCE.getHourLabels()[index];
|
||||
index++;
|
||||
i++;
|
||||
|
||||
//block
|
||||
SimplePanel hourWrapper = new SimplePanel();
|
||||
hourWrapper.setStylePrimaryName(TIME_LABEL_STYLE);
|
||||
hourWrapper.setHeight((labelHeight + FormattingUtil.getBorderOffset()) + "px");
|
||||
|
||||
FlowPanel flowPanel = new FlowPanel();
|
||||
flowPanel.setStyleName("hour-layout");
|
||||
|
||||
String amPm = " ";
|
||||
|
||||
if (index < 13)
|
||||
amPm += CalendarFormat.INSTANCE.getAm();
|
||||
else if (index > 13)
|
||||
amPm += CalendarFormat.INSTANCE.getPm();
|
||||
else {
|
||||
if (CalendarFormat.INSTANCE.isUseNoonLabel()) {
|
||||
hour = CalendarFormat.INSTANCE.getNoon();
|
||||
amPm = "";
|
||||
} else {
|
||||
amPm += CalendarFormat.INSTANCE.getPm();
|
||||
}
|
||||
}
|
||||
|
||||
Label hourLabel = new Label(hour);
|
||||
hourLabel.setStylePrimaryName("hour-text");
|
||||
flowPanel.add(hourLabel);
|
||||
|
||||
Label amPmLabel = new Label(amPm);
|
||||
amPmLabel.setStylePrimaryName("ampm-text");
|
||||
flowPanel.add(amPmLabel);
|
||||
|
||||
hourWrapper.add(flowPanel);
|
||||
|
||||
timelinePanel.add(hourWrapper);
|
||||
}
|
||||
}
|
||||
}
|
571
src/com/bradrydzewski/gwt/calendar/client/techview/TechView.java
Normal file
571
src/com/bradrydzewski/gwt/calendar/client/techview/TechView.java
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.allen_sauer.gwt.dnd.client.DragEndEvent;
|
||||
import com.allen_sauer.gwt.dnd.client.DragHandler;
|
||||
import com.allen_sauer.gwt.dnd.client.DragStartEvent;
|
||||
import com.allen_sauer.gwt.dnd.client.PickupDragController;
|
||||
import com.allen_sauer.gwt.dnd.client.VetoDragException;
|
||||
import com.allen_sauer.gwt.dnd.client.drop.DayViewDropController;
|
||||
import com.allen_sauer.gwt.dnd.client.drop.DayViewPickupDragController;
|
||||
import com.allen_sauer.gwt.dnd.client.drop.DayViewResizeController;
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarSettings.Click;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarView;
|
||||
import com.bradrydzewski.gwt.calendar.client.CalendarWidget;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.DaySelectionHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.event.WeekSelectionHandler;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.AppointmentUtil;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
import com.google.gwt.dom.client.Document;
|
||||
import com.google.gwt.dom.client.NativeEvent;
|
||||
import com.google.gwt.event.shared.HandlerRegistration;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
import com.google.gwt.user.client.Event;
|
||||
import com.google.gwt.user.client.Window;
|
||||
|
||||
public class TechView extends CalendarView {
|
||||
|
||||
private DayViewHeader dayViewHeader = null;
|
||||
private DayViewBody dayViewBody = null;
|
||||
private DayViewMultiDayBody multiViewBody = null;
|
||||
private TechViewLayoutStrategy layoutStrategy = null;
|
||||
|
||||
private final List<AppointmentWidget> appointmentWidgets = new ArrayList<AppointmentWidget>();
|
||||
/**
|
||||
* List of AppointmentAdapter objects that represent the currently selected
|
||||
* appointment.
|
||||
*/
|
||||
private List<AppointmentWidget> selectedAppointmentWidgets = new ArrayList<AppointmentWidget>();
|
||||
|
||||
private final TechViewStyleManager styleManager = GWT.create(TechViewStyleManager.class);
|
||||
|
||||
private DayViewResizeController resizeController = null;
|
||||
|
||||
private DayViewDropController dropController = null;
|
||||
|
||||
private PickupDragController dragController = null;
|
||||
|
||||
private DayViewResizeController proxyResizeController = null;
|
||||
|
||||
public TechView() {
|
||||
super();
|
||||
}
|
||||
|
||||
private int getMaxProxyHeight() {
|
||||
// For a comfortable use, the Proxy should be, top 2/3 (66%) of the view
|
||||
return (2 * (dayViewBody.getScrollPanel().getOffsetHeight() / 3));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public void doLayout() {
|
||||
// PERFORM APPOINTMENT LAYOUT NOW
|
||||
final Date date = (Date) calendarWidget.getDate().clone();
|
||||
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
multiViewBody.setDays((Date) date.clone(), calendarWidget.getDays());
|
||||
}
|
||||
|
||||
dayViewHeader.setDays((Date) date.clone(), calendarWidget.getDays());
|
||||
dayViewHeader.setYear((Date) date.clone());
|
||||
dayViewBody.setDays((Date) date.clone(), calendarWidget.getDays());
|
||||
dayViewBody.getTimeline().prepare();
|
||||
|
||||
dropController.setColumns(calendarWidget.getDays());
|
||||
dropController.setIntervalsPerHour(calendarWidget.getSettings().getIntervalsPerHour());
|
||||
dropController.setDayStartsAt(getSettings().getDayStartsAt());
|
||||
dropController.setDate((Date)calendarWidget.getDate().clone());
|
||||
dropController.setSnapSize(
|
||||
calendarWidget.getSettings().getPixelsPerInterval());
|
||||
dropController.setMaxProxyHeight(getMaxProxyHeight());
|
||||
resizeController.setIntervalsPerHour(
|
||||
calendarWidget.getSettings().getIntervalsPerHour());
|
||||
resizeController.setDayStartsAt(getSettings().getDayStartsAt());
|
||||
resizeController.setSnapSize(
|
||||
calendarWidget.getSettings().getPixelsPerInterval());
|
||||
proxyResizeController.setSnapSize(calendarWidget.getSettings().getPixelsPerInterval());
|
||||
proxyResizeController.setIntervalsPerHour(calendarWidget.getSettings().getIntervalsPerHour());
|
||||
proxyResizeController.setDayStartsAt(getSettings().getDayStartsAt());
|
||||
|
||||
this.selectedAppointmentWidgets.clear();
|
||||
appointmentWidgets.clear();
|
||||
|
||||
// HERE IS WHERE WE DO THE LAYOUT
|
||||
Date startDate = (Date) calendarWidget.getDate().clone();
|
||||
Date endDate = (Date) calendarWidget.getDate().clone();
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
DateUtils.resetTime(startDate);
|
||||
DateUtils.resetTime(endDate);
|
||||
|
||||
startDate.setHours(startDate.getHours());
|
||||
endDate.setHours(endDate.getHours());
|
||||
|
||||
for (int i = 0; i < calendarWidget.getDays(); i++) {
|
||||
|
||||
List<Appointment> filteredList = AppointmentUtil
|
||||
.filterListByDate(calendarWidget.getAppointments(), startDate, endDate);
|
||||
|
||||
// perform layout
|
||||
List<AppointmentAdapter> appointmentAdapters = layoutStrategy
|
||||
.doLayout(filteredList, i, calendarWidget.getDays());
|
||||
|
||||
// add all appointments back to the grid
|
||||
addAppointmentsToGrid(appointmentAdapters, false);
|
||||
|
||||
startDate.setDate(startDate.getDate() + 1);
|
||||
endDate.setDate(endDate.getDate() + 1);
|
||||
}
|
||||
|
||||
List<Appointment> filteredList =
|
||||
AppointmentUtil.filterListByDateRange(calendarWidget.getAppointments(),
|
||||
calendarWidget.getDate(), calendarWidget.getDays());
|
||||
|
||||
ArrayList<AppointmentAdapter> adapterList = new ArrayList<AppointmentAdapter>();
|
||||
int desiredHeight = layoutStrategy.doMultiDayLayout(filteredList,
|
||||
adapterList, calendarWidget.getDate(), calendarWidget.getDays());
|
||||
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
multiViewBody.grid.setHeight(desiredHeight + "px");
|
||||
|
||||
addAppointmentsToGrid(adapterList, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the Appointments to the view.
|
||||
* @param appointmentList List of Appointments
|
||||
* @param addToMultiView <code>true</code> if is adding the appointments to the multiview section, <code>false</code> otherwise
|
||||
*/
|
||||
private void addAppointmentsToGrid(final List<AppointmentAdapter> appointmentList, final boolean addToMultiView) {
|
||||
for (AppointmentAdapter appt : appointmentList) {
|
||||
AppointmentWidget panel = new AppointmentWidget();
|
||||
panel.setWidth(appt.getWidth());
|
||||
panel.setHeight(appt.getHeight());
|
||||
panel.setTitle(appt.getAppointment().getTitle());
|
||||
panel.setTop(appt.getTop());
|
||||
panel.setLeft(appt.getLeft());
|
||||
panel.setAppointment(appt.getAppointment());
|
||||
|
||||
boolean selected = calendarWidget.isTheSelectedAppointment(panel
|
||||
.getAppointment());
|
||||
if (selected) {
|
||||
selectedAppointmentWidgets.add(panel);
|
||||
}
|
||||
styleManager.applyStyle(panel, selected);
|
||||
appointmentWidgets.add(panel);
|
||||
|
||||
if (addToMultiView) {
|
||||
panel.setMultiDay(true);
|
||||
this.multiViewBody.grid.add(panel);
|
||||
} else {
|
||||
panel.setDescription(appt.getAppointment().getDescription());
|
||||
dayViewBody.getGrid().grid.add(panel);
|
||||
|
||||
//make footer 'draggable'
|
||||
if (calendarWidget.getSettings().isEnableDragDrop() && !appt.getAppointment().isReadOnly()) {
|
||||
resizeController.makeDraggable(panel.getResizeHandle());
|
||||
dragController.makeDraggable(panel, panel.getMoveHandle());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollToHour(final int hour) {
|
||||
dayViewBody.getScrollPanel().setVerticalScrollPosition((hour - getSettings().getDayStartsAt()) *
|
||||
getSettings().getIntervalsPerHour() * getSettings().getPixelsPerInterval());
|
||||
}
|
||||
|
||||
public void doSizing() {
|
||||
|
||||
if (calendarWidget.getOffsetHeight() > 0) {
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
dayViewBody.setHeight(calendarWidget.getOffsetHeight() - 2
|
||||
- dayViewHeader.getOffsetHeight()
|
||||
- multiViewBody.getOffsetHeight() + "px");
|
||||
} else {
|
||||
dayViewBody.setHeight(calendarWidget.getOffsetHeight() - 2
|
||||
- dayViewHeader.getOffsetHeight() + "px");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeleteKeyPressed() {
|
||||
if (calendarWidget.getSelectedAppointment() != null) {
|
||||
calendarWidget.fireDeleteEvent(calendarWidget.getSelectedAppointment());
|
||||
}
|
||||
}
|
||||
|
||||
public void onDoubleClick(Element element, Event event) {
|
||||
|
||||
List<AppointmentWidget> list = findAppointmentWidgetsByElement(element);
|
||||
if (!list.isEmpty()) {
|
||||
Appointment appt = list.get(0).getAppointment();
|
||||
//if (appt.equals(calendarWidget.getSelectedAppointment()))
|
||||
calendarWidget.fireOpenEvent(appt);
|
||||
// exit out
|
||||
} else if (getSettings().getTimeBlockClickNumber() == Click.Double
|
||||
&& element == dayViewBody.getGrid().gridOverlay.getElement()) {
|
||||
int x = DOM.eventGetClientX(event) + Window.getScrollLeft();
|
||||
int y = DOM.eventGetClientY(event) + Window.getScrollTop();
|
||||
timeBlockClick(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void onSingleClick(final Element element, final Event event) {
|
||||
|
||||
// Ignore the scroll panel
|
||||
if (dayViewBody.getScrollPanel().getElement().equals(element)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Appointment appointment = findAppointmentByElement(element);
|
||||
|
||||
if (appointment != null) {
|
||||
selectAppointment(appointment);
|
||||
} else if ((getSettings().getTimeBlockClickNumber() == Click.Single
|
||||
|| getSettings().getTimeBlockClickNumber() == Click.Drag)
|
||||
&& element == dayViewBody.getGrid().gridOverlay
|
||||
.getElement()) {
|
||||
int x = DOM.eventGetClientX(event) + Window.getScrollLeft();
|
||||
int y = DOM.eventGetClientY(event) + Window.getScrollTop();
|
||||
timeBlockClick(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
public void onMouseOver(final Element element, final Event event) {
|
||||
Appointment appointment = findAppointmentByElement(element);
|
||||
calendarWidget.fireMouseOverEvent(appointment, element);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAppointmentSelected(Appointment appointment) {
|
||||
|
||||
List<AppointmentWidget> clickedAppointmentAdapters =
|
||||
findAppointmentWidget(appointment);
|
||||
|
||||
if (!clickedAppointmentAdapters.isEmpty()) {
|
||||
for (AppointmentWidget adapter : selectedAppointmentWidgets) {
|
||||
styleManager.applyStyle(adapter, false);
|
||||
}
|
||||
|
||||
for (AppointmentWidget adapter : clickedAppointmentAdapters) {
|
||||
styleManager.applyStyle(adapter, true);
|
||||
}
|
||||
|
||||
selectedAppointmentWidgets.clear();
|
||||
selectedAppointmentWidgets = clickedAppointmentAdapters;
|
||||
|
||||
float height = clickedAppointmentAdapters.get(0).getHeight();
|
||||
// scrollIntoView ONLY if the appointment fits in the viewable area
|
||||
if (dayViewBody.getScrollPanel().getOffsetHeight() > height) {
|
||||
DOM.scrollIntoView(clickedAppointmentAdapters.get(0).getElement());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onRightArrowKeyPressed() {
|
||||
calendarWidget.selectNextAppointment();
|
||||
}
|
||||
|
||||
public void onUpArrowKeyPressed() {
|
||||
calendarWidget.selectPreviousAppointment();
|
||||
}
|
||||
|
||||
public void onDownArrowKeyPressed() {
|
||||
calendarWidget.selectNextAppointment();
|
||||
}
|
||||
|
||||
public void onLeftArrowKeyPressed() {
|
||||
calendarWidget.selectPreviousAppointment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStyleName() {
|
||||
return "gwt-cal";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void attach(CalendarWidget widget) {
|
||||
super.attach(widget);
|
||||
|
||||
if (dayViewBody == null) {
|
||||
dayViewBody = new DayViewBody(this);
|
||||
dayViewHeader = new DayViewHeader(this);
|
||||
layoutStrategy = new TechViewLayoutStrategy(this);
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
multiViewBody = new DayViewMultiDayBody(this);
|
||||
}
|
||||
}
|
||||
|
||||
calendarWidget.getRootPanel().add(dayViewHeader);
|
||||
if (getSettings().isMultidayVisible()) {
|
||||
calendarWidget.getRootPanel().add(multiViewBody);
|
||||
}
|
||||
calendarWidget.getRootPanel().add(dayViewBody);
|
||||
|
||||
if (getSettings() != null) {
|
||||
scrollToHour(getSettings().getScrollToHour());
|
||||
}
|
||||
|
||||
// Creates the different Controllers, if needed
|
||||
createDragController();
|
||||
createDropController();
|
||||
createResizeController();
|
||||
}
|
||||
|
||||
private void createDragController() {
|
||||
if (dragController == null) {
|
||||
dragController = new DayViewPickupDragController(dayViewBody.getGrid().grid, false);
|
||||
dragController.setBehaviorDragProxy(true);
|
||||
dragController.setBehaviorDragStartSensitivity(1);
|
||||
dragController.setBehaviorConstrainedToBoundaryPanel(true); //do I need these?
|
||||
dragController.setConstrainWidgetToBoundaryPanel(true); //do I need these?
|
||||
dragController.setBehaviorMultipleSelection(false);
|
||||
dragController.addDragHandler(new DragHandler(){
|
||||
|
||||
public void onDragEnd(DragEndEvent event) {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable).getAppointment();
|
||||
calendarWidget.setCommittedAppointment(appt);
|
||||
calendarWidget.fireUpdateEvent(appt);
|
||||
}
|
||||
|
||||
public void onDragStart(DragStartEvent event) {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable).getAppointment();
|
||||
calendarWidget.setRollbackAppointment(appt.clone());
|
||||
((DayViewPickupDragController)dragController).setMaxProxyHeight(getMaxProxyHeight());
|
||||
}
|
||||
|
||||
public void onPreviewDragEnd(DragEndEvent event)
|
||||
throws VetoDragException {
|
||||
}
|
||||
|
||||
public void onPreviewDragStart(DragStartEvent event)
|
||||
throws VetoDragException {
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void createDropController() {
|
||||
if (dropController==null) {
|
||||
dropController = new DayViewDropController(dayViewBody.getGrid().grid);
|
||||
dragController.registerDropController(dropController);
|
||||
}
|
||||
}
|
||||
|
||||
private void createResizeController() {
|
||||
if (resizeController == null) {
|
||||
resizeController = new DayViewResizeController(dayViewBody.getGrid().grid);
|
||||
resizeController.addDragHandler(new DragHandler(){
|
||||
|
||||
public void onDragEnd(DragEndEvent event) {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable.getParent()).getAppointment();
|
||||
calendarWidget.setCommittedAppointment(appt);
|
||||
calendarWidget.fireUpdateEvent(appt);
|
||||
}
|
||||
|
||||
public void onDragStart(DragStartEvent event) {
|
||||
calendarWidget
|
||||
.setRollbackAppointment(((AppointmentWidget) event
|
||||
.getContext().draggable.getParent()).getAppointment()
|
||||
.clone());
|
||||
}
|
||||
|
||||
public void onPreviewDragEnd(DragEndEvent event)
|
||||
throws VetoDragException {}
|
||||
public void onPreviewDragStart(DragStartEvent event)
|
||||
throws VetoDragException {}
|
||||
});
|
||||
}
|
||||
|
||||
if(proxyResizeController == null) {
|
||||
proxyResizeController = new DayViewResizeController(dayViewBody.getGrid().grid);
|
||||
proxyResizeController.addDragHandler(new DragHandler(){
|
||||
long startTime = 0L;
|
||||
int initialX = 0;
|
||||
int initialY = 0;
|
||||
Date startDate;
|
||||
|
||||
public void onDragEnd(DragEndEvent event) {
|
||||
long clickTime = System.currentTimeMillis() - startTime;
|
||||
int y = event.getContext().mouseY;
|
||||
if (clickTime <= 500 && initialY == y) {
|
||||
calendarWidget.fireTimeBlockClickEvent(startDate);
|
||||
} else {
|
||||
Appointment appt = ((AppointmentWidget) event.getContext().draggable.getParent()).getAppointment();
|
||||
calendarWidget.setCommittedAppointment(appt);
|
||||
calendarWidget.fireCreateEvent(appt);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDragStart(DragStartEvent event) {
|
||||
startTime = System.currentTimeMillis();
|
||||
initialX = event.getContext().mouseX;
|
||||
initialY = event.getContext().mouseY;
|
||||
startDate = getCoordinatesDate(initialX, initialY);
|
||||
calendarWidget.setRollbackAppointment(null);
|
||||
}
|
||||
|
||||
public void onPreviewDragEnd(DragEndEvent event)
|
||||
throws VetoDragException {}
|
||||
public void onPreviewDragStart(DragStartEvent event)
|
||||
throws VetoDragException {}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private Date getCoordinatesDate(int x, int y) {
|
||||
int left = dayViewBody.getGrid().gridOverlay.getAbsoluteLeft();
|
||||
int top = dayViewBody.getScrollPanel().getAbsoluteTop();
|
||||
int width = dayViewBody.getGrid().gridOverlay.getOffsetWidth();
|
||||
int scrollOffset = dayViewBody.getScrollPanel().getVerticalScrollPosition();
|
||||
|
||||
// x & y are based on screen position,need to get x/y relative to
|
||||
// component
|
||||
int relativeY = y - top + scrollOffset;
|
||||
int relativeX = x - left;
|
||||
|
||||
// find the interval clicked and day clicked
|
||||
double interval = Math.floor(relativeY
|
||||
/ (double) getSettings().getPixelsPerInterval());
|
||||
double day = Math.floor((double) relativeX
|
||||
/ ((double) width / (double) calendarWidget.getDays()));
|
||||
|
||||
// create new appointment date based on click
|
||||
Date newStartDate = calendarWidget.getDate();
|
||||
newStartDate.setHours(getSettings().getDayStartsAt());
|
||||
newStartDate.setMinutes(0);
|
||||
newStartDate.setSeconds(0);
|
||||
newStartDate.setMinutes((int) interval
|
||||
* (60 / getSettings().getIntervalsPerHour()));
|
||||
newStartDate.setDate(newStartDate.getDate() + (int) day);
|
||||
|
||||
return newStartDate;
|
||||
}
|
||||
|
||||
private void timeBlockClick(int x, int y) {
|
||||
int left = dayViewBody.getGrid().gridOverlay.getAbsoluteLeft();
|
||||
int top = dayViewBody.getScrollPanel().getAbsoluteTop();
|
||||
int width = dayViewBody.getGrid().gridOverlay.getOffsetWidth();
|
||||
int scrollOffset = dayViewBody.getScrollPanel().getVerticalScrollPosition();
|
||||
|
||||
// x & y are based on screen position,need to get x/y relative to
|
||||
// component
|
||||
int relativeY = y - top + scrollOffset;
|
||||
int relativeX = x - left;
|
||||
|
||||
// find the interval clicked and day clicked
|
||||
double day = Math.floor((double) relativeX
|
||||
/ ((double) width / (double) calendarWidget.getDays()));
|
||||
|
||||
Date newStartDate = getCoordinatesDate(x, y);
|
||||
|
||||
if (getSettings().getTimeBlockClickNumber() != Click.Drag) {
|
||||
calendarWidget.fireTimeBlockClickEvent(newStartDate);
|
||||
} else {
|
||||
int snapSize = calendarWidget.getSettings().getPixelsPerInterval();
|
||||
// Create the proxy
|
||||
width = width / calendarWidget.getDays();
|
||||
left = (int) day * width;
|
||||
// Adjust the start to the closest interval
|
||||
top = (int)Math.floor(
|
||||
(float) relativeY / snapSize) * snapSize;
|
||||
|
||||
AppointmentWidget proxy = new AppointmentWidget();
|
||||
Appointment app = new Appointment();
|
||||
app.setStart(newStartDate);
|
||||
app.setEnd(newStartDate);
|
||||
proxy.setAppointment(app);
|
||||
proxy.setStart(newStartDate);
|
||||
proxy.setPixelSize(width, /*height*/ snapSize);
|
||||
dayViewBody.getGrid().grid.add(proxy, left, top);
|
||||
styleManager.applyStyle(proxy, false);
|
||||
proxyResizeController.makeDraggable(proxy.getResizeHandle());
|
||||
|
||||
NativeEvent evt = Document.get().createMouseDownEvent(1, 0, 0, x, y, false,
|
||||
false, false, false, NativeEvent.BUTTON_LEFT);
|
||||
proxy.getResizeHandle().getElement().dispatchEvent(evt);
|
||||
}
|
||||
}
|
||||
|
||||
private List<AppointmentWidget> findAppointmentWidgetsByElement(
|
||||
Element element) {
|
||||
return findAppointmentWidget(findAppointmentByElement(element));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Appointment} indirectly associated to the passed
|
||||
* <code>element</code>. Each Appointment drawn on the CalendarView maps to
|
||||
* a Widget and therefore an Element. This method attempts to find an
|
||||
* Appointment based on the provided Element. If no match is found a null
|
||||
* value is returned.
|
||||
*
|
||||
* @param element
|
||||
* Element to look up.
|
||||
* @return Appointment matching the element.
|
||||
*/
|
||||
private Appointment findAppointmentByElement(Element element) {
|
||||
Appointment appointmentAtElement = null;
|
||||
for (AppointmentWidget widget : appointmentWidgets) {
|
||||
if (DOM.isOrHasChild(widget.getElement(), element)) {
|
||||
appointmentAtElement = widget.getAppointment();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return appointmentAtElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds any related adapters that match the given Appointment.
|
||||
*
|
||||
* @param appt
|
||||
* Appointment to match.
|
||||
* @return List of related AppointmentWidget objects.
|
||||
*/
|
||||
private List<AppointmentWidget> findAppointmentWidget(Appointment appt) {
|
||||
ArrayList<AppointmentWidget> appointmentAdapters = new ArrayList<AppointmentWidget>();
|
||||
if (appt != null) {
|
||||
for (AppointmentWidget widget : appointmentWidgets) {
|
||||
if (widget.getAppointment().equals(appt)) {
|
||||
appointmentAdapters.add(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
return appointmentAdapters;
|
||||
}
|
||||
|
||||
public HandlerRegistration addWeekSelectionHandler(
|
||||
WeekSelectionHandler<Date> handler) {
|
||||
return dayViewHeader.addWeekSelectionHandler(handler);
|
||||
}
|
||||
|
||||
public HandlerRegistration addDaySelectionHandler(
|
||||
DaySelectionHandler<Date> handler) {
|
||||
return dayViewHeader.addDaySelectionHandler(handler);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,440 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
import com.bradrydzewski.gwt.calendar.client.HasSettings;
|
||||
import com.bradrydzewski.gwt.calendar.client.util.AppointmentUtil;
|
||||
|
||||
/**
|
||||
* Responsible for arranging all Appointments, visually, on a screen in a manner
|
||||
* similar to the Microsoft Outlook / Windows Vista calendar.
|
||||
* See: <img src='http://www.microsoft.com/library/media/1033/athome/images/moredone/calendar.gif'/>
|
||||
* <p>
|
||||
* Note how overlapping appointments are displayed in the provided image
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @version 1.0 6/07/09
|
||||
* @since 1.0
|
||||
*/
|
||||
public class TechViewLayoutStrategy {
|
||||
|
||||
private static final int MINUTES_PER_HOUR = 60;
|
||||
private static final int HOURS_PER_DAY = 24;
|
||||
private final HasSettings settings;
|
||||
|
||||
public TechViewLayoutStrategy(final HasSettings settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
public List<AppointmentAdapter> doLayout(List<Appointment> appointments, int dayIndex, int dayCount) {
|
||||
|
||||
int intervalsPerHour = settings.getSettings().getIntervalsPerHour(); //30 minute intervals
|
||||
float intervalSize = settings.getSettings().getPixelsPerInterval(); //25 pixels per interval
|
||||
|
||||
/*
|
||||
* Note: it is important that all appointments are sorted by Start date
|
||||
* (asc) and Duration (desc) for this algorithm to work. If that is not
|
||||
* the case, it won't work, at all!! Maybe this is a problem that needs
|
||||
* to be addressed
|
||||
*/
|
||||
|
||||
// set to 30 minutes. this means there will be 48 cells. 60min / 30min
|
||||
// interval * 24
|
||||
//int minutesPerInterval = 30;
|
||||
// interval size, set to 100px
|
||||
//float sizeOfInterval = 25f;
|
||||
|
||||
// a calendar can view multiple days at a time. sets number of visible
|
||||
// days
|
||||
// TODO: use this later, not currently implemented
|
||||
// float numberOfDays = dates.size();
|
||||
|
||||
int minutesPerInterval = MINUTES_PER_HOUR / intervalsPerHour;
|
||||
|
||||
// get number of cells (time blocks)
|
||||
int numberOfTimeBlocks = MINUTES_PER_HOUR / minutesPerInterval * HOURS_PER_DAY;
|
||||
TimeBlock[] timeBlocks = new TimeBlock[numberOfTimeBlocks];
|
||||
|
||||
for (int i = 0; i < numberOfTimeBlocks; i++) {
|
||||
TimeBlock t = new TimeBlock();
|
||||
t.setStart(i * minutesPerInterval);
|
||||
t.setEnd(t.getStart() + minutesPerInterval);
|
||||
t.setOrder(i);
|
||||
t.setTop((float) i * intervalSize);
|
||||
t.setBottom(t.getTop() + intervalSize);
|
||||
timeBlocks[i] = t;
|
||||
}
|
||||
|
||||
// each appointment will get "wrapped" in an appoinetment cell object,
|
||||
// so that we can assign it a location in the grid, row and
|
||||
// column span, etc.
|
||||
ArrayList<AppointmentAdapter> appointmentCells = new ArrayList<AppointmentAdapter>();
|
||||
// Map<TimeBlock,TimeBlock> blockGroup = new
|
||||
// HashMap<TimeBlock,TimeBlock>();
|
||||
int groupMaxColumn = 0; // track total columns here! this will reset
|
||||
// when a group completes
|
||||
int groupStartIndex = -1;
|
||||
int groupEndIndex = -2;
|
||||
|
||||
// Question: how to distinguish start / finish of a new group?
|
||||
// Answer: when endCell of previous appointments < startCell of new
|
||||
// appointment
|
||||
|
||||
// for each appointments, we need to see if it intersects with each time
|
||||
// block
|
||||
for (Appointment appointment : appointments) {
|
||||
|
||||
TimeBlock startBlock = null;
|
||||
TimeBlock endBlock = null;
|
||||
|
||||
// if(blockGroupEndCell)
|
||||
|
||||
// wrap appointment with AppointmentInterface Cell and add to list
|
||||
AppointmentAdapter apptCell = new AppointmentAdapter(appointment);
|
||||
appointmentCells.add(apptCell);
|
||||
|
||||
// get the first time block in which the appointment should appear
|
||||
// TODO: since appointments are sorted, we should never need to
|
||||
// re-evaluate a time block that had zero matches...
|
||||
// store the index of the currently evaluated time block, if no
|
||||
// match, increment
|
||||
// that will prevent the same block from ever being re-evaluated
|
||||
// after no match found
|
||||
for (TimeBlock block : timeBlocks) {
|
||||
// does the appointment intersect w/ the block???
|
||||
if (block.intersectsWith(apptCell)) {
|
||||
|
||||
// we found one! set as start block and exit loop
|
||||
startBlock = block;
|
||||
// blockGroup.put(block, block);
|
||||
|
||||
if (groupEndIndex < startBlock.getOrder()) {
|
||||
|
||||
//System.out.println(" prior group max cols: "
|
||||
// + groupMaxColumn);
|
||||
|
||||
for (int i = groupStartIndex; i <= groupEndIndex; i++) {
|
||||
|
||||
TimeBlock tb = timeBlocks[i];
|
||||
tb.setTotalColumns(groupMaxColumn + 1);
|
||||
//System.out.println(" total col set for block: "
|
||||
// + i);
|
||||
}
|
||||
groupStartIndex = startBlock.getOrder();
|
||||
//System.out.println("new group at: " + groupStartIndex);
|
||||
groupMaxColumn = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
} else {
|
||||
// here is where I would increment, as per above to-do
|
||||
}
|
||||
}
|
||||
|
||||
// add the appointment to the start block
|
||||
startBlock.getAppointments().add(apptCell);
|
||||
// add block to appointment
|
||||
apptCell.getIntersectingBlocks().add(startBlock);
|
||||
|
||||
// set the appointments column, if it has not already been set
|
||||
// if it has been set, we need to get it for reference later on in
|
||||
// this method
|
||||
// int column = startBlock.getFirstAvailableColumn();
|
||||
int column = appointment.getColumnId();
|
||||
apptCell.setColumnStart(column);
|
||||
apptCell.setColumnSpan(1); // hard-code to 1, for now
|
||||
|
||||
// we track the max column for a time block
|
||||
// if a column get's added make sure we increment
|
||||
// if (startBlock.getTotalColumns() <= column) {
|
||||
// startBlock.setTotalColumns(column+1);
|
||||
// }
|
||||
|
||||
// add column to block's list of occupied columns, so that the
|
||||
// column cannot be given to another appointment
|
||||
startBlock.getOccupiedColumns().put(column, column);
|
||||
|
||||
// sets the start cell of the appt to the current block
|
||||
// we can do this since the blocks are ordered ascending
|
||||
apptCell.setCellStart(startBlock.getOrder());
|
||||
|
||||
// go through all subsequent blocks...
|
||||
// find intersections
|
||||
for (int i = startBlock.getOrder() + 1; i < timeBlocks.length; i++) {
|
||||
|
||||
// get the nextTimeBlock
|
||||
TimeBlock nextBlock = timeBlocks[i];
|
||||
|
||||
// exit look if end date > block start, since no subsequent
|
||||
// blocks will ever intersect
|
||||
// if (apptCell.getAppointmentEnd() > nextBlock.getStart()) {
|
||||
// break; //does appt intersect with this block?
|
||||
// }
|
||||
if (nextBlock.intersectsWith(apptCell)) {
|
||||
|
||||
// yes! add appointment to the block
|
||||
// register start column
|
||||
nextBlock.getAppointments().add(apptCell);
|
||||
nextBlock.getOccupiedColumns().put(column, column);
|
||||
endBlock = nextBlock; // this may change if intersects with
|
||||
// next block
|
||||
|
||||
// add block to appointments list of intersecting blocks
|
||||
apptCell.getIntersectingBlocks().add(nextBlock);
|
||||
|
||||
// we track the max column for a time block
|
||||
// if a column get's added make sure we increment
|
||||
// if (nextBlock.getTotalColumns() <= column) {
|
||||
// nextBlock.setTotalColumns(column+1);
|
||||
// }
|
||||
|
||||
// blockGroup.put(nextBlock, nextBlock);
|
||||
}
|
||||
}
|
||||
|
||||
// if end block was never set, use the start block
|
||||
endBlock = (endBlock == null) ? startBlock : endBlock;
|
||||
// maybe here is the "end" of a group, where we then evaluate max
|
||||
// column
|
||||
|
||||
if (column > groupMaxColumn) {
|
||||
groupMaxColumn = column;
|
||||
// System.out.println(" max col: " + groupMaxColumn);
|
||||
}
|
||||
|
||||
if (groupEndIndex < endBlock.getOrder()) {
|
||||
groupEndIndex = endBlock.getOrder();
|
||||
//System.out.println(" end index (re)set: " + groupEndIndex);
|
||||
}
|
||||
// for(int i = groupStartIndex; i<=groupEndIndex; i++) {
|
||||
// timeBlocks[i].setTotalColumns(groupMaxColumn);
|
||||
// }
|
||||
// groupMaxColumn=1;
|
||||
// }
|
||||
|
||||
// for(TimeBlock timeBlock : blockGroup.values()) {
|
||||
//
|
||||
// }
|
||||
|
||||
// blockGroup = new HashMap<TimeBlock,TimeBlock>();
|
||||
|
||||
// set the appointments cell span (top to bottom)
|
||||
apptCell.setCellSpan(endBlock.getOrder() - startBlock.getOrder() + 1);
|
||||
|
||||
}
|
||||
for (int i = groupStartIndex; i <= groupEndIndex; i++) {
|
||||
|
||||
TimeBlock tb = timeBlocks[i];
|
||||
tb.setTotalColumns(groupMaxColumn + 1);
|
||||
//System.out.println(" total col set for block: " + i);
|
||||
}
|
||||
// we need to know the MAX number of cells for each time block.
|
||||
// so unfortunately we have to go back through the list to find this out
|
||||
/*
|
||||
* for(AppointmentCell apptCell : appointmentCells) {
|
||||
*
|
||||
* for (TimeBlock block : apptCell.getIntersectingBlocks()) {
|
||||
*
|
||||
* int maxCol = 0;
|
||||
*
|
||||
* //find the max cell for (AppointmentCell apptCell :
|
||||
* block.getAppointments()) { int col = apptCell.getColumnStart(); if
|
||||
* (col > maxCol) { maxCol = col; } }
|
||||
*
|
||||
* block.setTotalColumns(maxCol+1); } }
|
||||
*/
|
||||
|
||||
|
||||
//last step is to calculate the adjustment reuired for 'multi-day' / multi-column
|
||||
float widthAdj = 1f / dayCount;
|
||||
|
||||
float paddingLeft = .5f;
|
||||
float paddingRight = .5f;
|
||||
float paddingBottom = 2;
|
||||
|
||||
// now that everything has been assigned a cell, column and spans
|
||||
// we can calculate layout
|
||||
// Note: this can only be done after every single appointment has
|
||||
// been assigned a position in the grid
|
||||
for (AppointmentAdapter apptCell : appointmentCells) {
|
||||
|
||||
float width = 1f / (float) apptCell.getIntersectingBlocks().get(0).getTotalColumns() * 100;
|
||||
float left = (float) apptCell.getColumnStart() / (float) apptCell.getIntersectingBlocks().get(0).getTotalColumns() * 100;
|
||||
|
||||
//AppointmentInterface appt = apptCell.getAppointment();
|
||||
apptCell.setTop((float) apptCell.getCellStart() * intervalSize); // ok!
|
||||
apptCell.setLeft((widthAdj * 100 * dayIndex) + (left * widthAdj) + paddingLeft); // ok
|
||||
apptCell.setWidth(width * widthAdj - paddingLeft - paddingRight); // ok!
|
||||
apptCell.setHeight((float) apptCell.getIntersectingBlocks().size() * ((float) intervalSize) - paddingBottom); // ok!
|
||||
|
||||
float apptStart = apptCell.getAppointmentStart();
|
||||
float apptEnd = apptCell.getAppointmentEnd();
|
||||
float blockStart = timeBlocks[apptCell.getCellStart()].getStart();
|
||||
float blockEnd = timeBlocks[apptCell.getCellStart() + apptCell.getCellSpan() - 1].getEnd();
|
||||
float blockDuration = blockEnd - blockStart;
|
||||
float apptDuration = apptEnd - apptStart;
|
||||
float timeFillHeight = apptDuration / blockDuration * 100f;
|
||||
float timeFillStart = (apptStart - blockStart) / blockDuration * 100f;
|
||||
// System.out.println("apptStart: "+apptStart);
|
||||
// System.out.println("apptEnd: "+apptEnd);
|
||||
// System.out.println("blockStart: "+blockStart);
|
||||
// System.out.println("blockEnd: "+blockEnd);
|
||||
// System.out.println("timeFillHeight: "+timeFillHeight);
|
||||
//System.out.println("timeFillStart: "+timeFillStart);
|
||||
//System.out.println("------------");
|
||||
apptCell.setCellPercentFill(timeFillHeight);
|
||||
apptCell.setCellPercentStart(timeFillStart);
|
||||
//appt.formatTimeline(apptCell.getCellPercentStart(), apptCell.getCellPercentFill());
|
||||
}
|
||||
|
||||
return appointmentCells;
|
||||
}
|
||||
|
||||
public int doMultiDayLayout(List<Appointment> appointments, List<AppointmentAdapter> adapters, Date start, int days) {
|
||||
|
||||
//create array to hold all appointments for a particular day
|
||||
//HashMap<Date, ArrayList<AppointmentAdapter>> appointmentDayMap
|
||||
// = new HashMap<Date, ArrayList<AppointmentAdapter>>();
|
||||
|
||||
//for a particular day need to track all used rows
|
||||
HashMap<Integer, HashMap<Integer, Integer>> daySlotMap = new HashMap<Integer, HashMap<Integer, Integer>>();
|
||||
|
||||
int minHeight = 30;
|
||||
int maxRow = 0;
|
||||
|
||||
|
||||
//convert appointment to adapter
|
||||
for (Appointment appointment : appointments) {
|
||||
adapters.add(new AppointmentAdapter(appointment));
|
||||
}
|
||||
|
||||
//create array of dates
|
||||
ArrayList<Date> dateList = new ArrayList<Date>();
|
||||
Date tempStartDate = (Date)start.clone();
|
||||
|
||||
// tempStartDate.setHours(0);
|
||||
// tempStartDate.setMinutes(0);
|
||||
// tempStartDate.setSeconds(0);
|
||||
for (int i = 0; i < days; i++) {
|
||||
Date d = (Date) tempStartDate.clone();
|
||||
DateUtils.resetTime(d);
|
||||
//appointmentDayMap.put(d, new ArrayList<AppointmentAdapter>());
|
||||
daySlotMap.put(i, new HashMap<Integer, Integer>());
|
||||
dateList.add(d);
|
||||
DateUtils.moveOneDayForward(tempStartDate);
|
||||
}
|
||||
|
||||
|
||||
//add appointments to each day
|
||||
for (AppointmentAdapter adapter : adapters) {
|
||||
|
||||
int columnSpan = 0; //number of columns spanned
|
||||
boolean isStart = true; //indicates if current column is appointment start column
|
||||
|
||||
//set column & span
|
||||
for (int i = 0; i < dateList.size(); i++) {
|
||||
Date date = dateList.get(i);
|
||||
boolean isWithinRange =
|
||||
AppointmentUtil.rangeContains(
|
||||
adapter.getAppointment(), date);
|
||||
|
||||
//System.out.println(" isWithinRange == " + isWithinRange + " for start: " + adapter.getAppointment().getStart() + " end: " + adapter.getAppointment().getEnd() + " date: "+date);
|
||||
|
||||
//while we are at it, we can set the adapters start column
|
||||
// and colun span
|
||||
if (isWithinRange) {
|
||||
//appointmentDayMap.get(date).add(adapter);
|
||||
|
||||
if (isStart) {
|
||||
adapter.setColumnStart(i);
|
||||
isStart = false;
|
||||
}
|
||||
|
||||
adapter.setColumnSpan(columnSpan);
|
||||
columnSpan++;
|
||||
}
|
||||
}
|
||||
|
||||
//now we set the row, which cannot be more than total # of appointments
|
||||
for (int x = 0; x < adapters.size(); x++) {
|
||||
|
||||
boolean isRowOccupied = false;
|
||||
for (int y = adapter.getColumnStart(); y <= adapter.getColumnStart() + adapter.getColumnSpan(); y++) {
|
||||
try{
|
||||
HashMap<Integer, Integer> rowMap = daySlotMap.get(y);
|
||||
if (rowMap.containsKey(x)) {
|
||||
isRowOccupied = true;
|
||||
//System.out.println(" row [" + x+"] is occupied for day [" + y+"]");
|
||||
} else {
|
||||
//isRowOccupied = false;
|
||||
break; //break out of loop, nothing found in row slot
|
||||
}
|
||||
}catch(Exception ex) {
|
||||
//System.out.println("Exception: y=" + y + " x=" + x + " adapters.size=" + adapters.size() + " start="+adapter.getAppointment().getStart() + " end="+adapter.getAppointment().getEnd().toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (!isRowOccupied) {
|
||||
//add row to maps
|
||||
for (int y = adapter.getColumnStart(); y <= adapter.getColumnStart() + adapter.getColumnSpan(); y++) {
|
||||
HashMap<Integer, Integer> rowMap = daySlotMap.get(y);
|
||||
rowMap.put(x, x);
|
||||
if (x > maxRow) {
|
||||
maxRow = x;
|
||||
}
|
||||
//System.out.println(" > added "+ x + " to row list for column " + y);
|
||||
}
|
||||
//set the row (also named cell)
|
||||
adapter.setCellStart(x);
|
||||
//break loop
|
||||
|
||||
|
||||
//now we set the appointment's location
|
||||
//Appointment appt = adapter.getAppointment();
|
||||
float top = adapter.getCellStart() * 25f + 5f;
|
||||
float width = ((float) adapter.getColumnSpan() + 1f) / days * 100f - 1f; //10f=padding
|
||||
float left = ((float) adapter.getColumnStart()) / days * 100f + .5f; //10f=padding
|
||||
//float left = (float) adapter.getColumnStart() / (float) apptCell.getIntersectingBlocks().get(0).getTotalColumns() * 100;
|
||||
adapter.setWidth(width);
|
||||
adapter.setLeft(left);
|
||||
adapter.setTop(top);
|
||||
adapter.setHeight(20);
|
||||
//System.out.println("set appointment [" + appt.getTitle() + "] layout left: " + left + " top: " + top + " width: " + width);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//System.out.println("multi-day layout -- title: \"" + adapter.getAppointment().getTitle() + "\" | col start: " + adapter.getColumnStart() + " | colspan: " + adapter.getColumnSpan() + " | row: " + adapter.getCellStart() + " | start date: " + adapter.getAppointment().getStart() + " | end date: " + adapter.getAppointment().getEnd());
|
||||
|
||||
|
||||
}
|
||||
|
||||
int height = (maxRow + 1) * 25 + 5;
|
||||
return Math.max(height, minHeight);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.ThemeAppointmentStyle;
|
||||
import com.google.gwt.user.client.DOM;
|
||||
import com.google.gwt.user.client.Element;
|
||||
|
||||
public abstract class TechViewStyleManager {
|
||||
|
||||
protected static final String APPOINTMENT_STYLE = "dv-appointment";
|
||||
|
||||
protected static final String APPOINTMENT_STYLE_SELECTED = "-selected";
|
||||
|
||||
protected static final String APPOINTMENT_STYLE_MULTIDAY = "-multiday";
|
||||
|
||||
protected static final String BACKGROUND_COLOR_STYLE_ATTRIBUTE = "backgroundColor";
|
||||
|
||||
protected static final String BACKGROUND_IMAGE_STYLE_ATTRIBUTE = "backgroundImage";
|
||||
|
||||
protected static final String BORDER_COLOR_STYLE_ATTRIBUTE = "borderColor";
|
||||
|
||||
protected static final String COLOR_STYLE_ATTRIBUTE = "color";
|
||||
|
||||
public void applyStyle(AppointmentWidget widget, boolean selected) {
|
||||
doApplyStyleInternal(widget, selected);
|
||||
}
|
||||
|
||||
protected abstract ThemeAppointmentStyle getViewAppointmentStyleForTheme(Appointment appointment);
|
||||
|
||||
protected abstract ThemeAppointmentStyle getDefaultViewAppointmentStyleForTheme();
|
||||
|
||||
private void doApplyStyleInternal(AppointmentWidget widget, boolean selected) {
|
||||
|
||||
// Extract the Appointment for later reference
|
||||
Appointment appointment = widget.getAppointment();
|
||||
// Extract the DOM Element for later reference
|
||||
Element elem = widget.getElement();
|
||||
Element bodyElem = widget.getBody().getElement();
|
||||
Element headerElem = widget.getHeader().getElement();
|
||||
// Is MultiDay?
|
||||
boolean multiDay = appointment.isMultiDay() || appointment.isAllDay();
|
||||
|
||||
//Lookup the style from the map
|
||||
ThemeAppointmentStyle style = getViewAppointmentStyleForTheme(appointment);
|
||||
|
||||
//Determine Style Name
|
||||
String styleName = APPOINTMENT_STYLE;
|
||||
if(multiDay) styleName+=APPOINTMENT_STYLE_MULTIDAY;
|
||||
if(selected) styleName+=APPOINTMENT_STYLE_SELECTED;
|
||||
widget.setStylePrimaryName(styleName);
|
||||
|
||||
//If no style is found, apply the default blue style
|
||||
//TODO: need to check for a custom style
|
||||
if(style==null)
|
||||
style = getDefaultViewAppointmentStyleForTheme();
|
||||
|
||||
if (multiDay)
|
||||
DOM.setStyleAttribute(elem, BACKGROUND_COLOR_STYLE_ATTRIBUTE, style.getBackgroundHeader());
|
||||
else
|
||||
DOM.setStyleAttribute(elem, BACKGROUND_COLOR_STYLE_ATTRIBUTE, style.getBackground());
|
||||
|
||||
DOM.setStyleAttribute(elem, BORDER_COLOR_STYLE_ATTRIBUTE, style.getBackgroundHeader());
|
||||
|
||||
DOM.setStyleAttribute(bodyElem, COLOR_STYLE_ATTRIBUTE, style.getSelectedBorder());
|
||||
|
||||
DOM.setStyleAttribute(headerElem, COLOR_STYLE_ATTRIBUTE, style.getHeaderText());
|
||||
|
||||
DOM.setStyleAttribute(headerElem, BACKGROUND_COLOR_STYLE_ATTRIBUTE, style.getBackgroundHeader());
|
||||
|
||||
if (multiDay)
|
||||
return;
|
||||
|
||||
if (selected && style.getSelectedBackgroundImage() != null) {
|
||||
DOM.setStyleAttribute(elem, BACKGROUND_IMAGE_STYLE_ATTRIBUTE, "url("+ style.getSelectedBackgroundImage() + ")");
|
||||
} else {
|
||||
DOM.setStyleAttribute(elem, BACKGROUND_IMAGE_STYLE_ATTRIBUTE, "none");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.techview;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents a block of time that contains one or many Appointments. An example
|
||||
* of a timeblock could be 10am - 10:30 am, where a block of time is 30 minutes.
|
||||
* <p> A block of time can contain or be interested by one or many appointments.
|
||||
* Using the above example, a time block from 10am - 10:30 am could contain the
|
||||
* following appointments:
|
||||
* <ul>
|
||||
* <li>10:00 - 10:30, where start / end are same as time block</li>
|
||||
* <li>9:00 - 10:30, where the appointment starts before the time block
|
||||
* starts but ends at same time as time block</li>
|
||||
* <li>9:00 - 10:20, where appointment start before
|
||||
* and ends after start of time block</li>
|
||||
* <li>9:00 - 11:00, where appointment starts before and ends after the time
|
||||
* block does</li>
|
||||
* <li>10:05 - 10:25, where appointment starts after but ends before the
|
||||
* time block</li> </ul></p>
|
||||
* Above
|
||||
* are example use cases of a time block and how it relates to an appointment.
|
||||
* Note that an appointment can intersect with one ore many time blocks. This
|
||||
* class holds a number of parameters allowing a time block to manage its
|
||||
* appointments and determine where the appointments should be arranged within
|
||||
* itself.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class TimeBlock {
|
||||
private List<AppointmentAdapter> appointments = new ArrayList<AppointmentAdapter>();
|
||||
private Map<Integer, Integer> occupiedColumns = new HashMap<Integer, Integer>();
|
||||
private int totalColumns = 1;
|
||||
private int order;
|
||||
private String name;
|
||||
private int start;
|
||||
private int end;
|
||||
private float top;
|
||||
private float bottom;
|
||||
|
||||
public List<AppointmentAdapter> getAppointments() {
|
||||
return appointments;
|
||||
}
|
||||
|
||||
public Map<Integer, Integer> getOccupiedColumns() {
|
||||
return occupiedColumns;
|
||||
}
|
||||
|
||||
public int getFirstAvailableColumn() {
|
||||
int col = 0;
|
||||
while (true) {
|
||||
if (occupiedColumns.containsKey(col))
|
||||
col++;
|
||||
else return col;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTotalColumns() {
|
||||
return totalColumns;
|
||||
}
|
||||
|
||||
public void setTotalColumns(int totalColumns) {
|
||||
this.totalColumns = totalColumns;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
public int getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(int end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
public int getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(int start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public float getBottom() {
|
||||
return bottom;
|
||||
}
|
||||
|
||||
public void setBottom(float bottom) {
|
||||
this.bottom = bottom;
|
||||
}
|
||||
|
||||
public float getTop() {
|
||||
return top;
|
||||
}
|
||||
|
||||
public void setTop(float top) {
|
||||
this.top = top;
|
||||
}
|
||||
|
||||
public boolean intersectsWith(int apptStart, int apptEnd) {
|
||||
//scenario 1: start date of appt between start and end of block
|
||||
if (apptStart >= this.getStart() && apptStart < this.getEnd())
|
||||
return true;
|
||||
|
||||
//scenario 2: end date of appt > block start date &
|
||||
// start date of appt before block start date
|
||||
return apptEnd > this.getStart() && apptStart < this.getStart();
|
||||
}
|
||||
|
||||
public boolean intersectsWith(AppointmentAdapter appt) {
|
||||
return intersectsWith(appt.getAppointmentStart(),
|
||||
appt.getAppointmentEnd());
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2010 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
package com.bradrydzewski.gwt.calendar.client.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.Appointment;
|
||||
import com.bradrydzewski.gwt.calendar.client.DateUtils;
|
||||
|
||||
/**
|
||||
* Utility class for several operations involving time and {@link Appointment}
|
||||
* objects.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
* @author Carlos D. Morales
|
||||
*/
|
||||
public class AppointmentUtil {
|
||||
|
||||
public static List<Appointment> filterListByDateRange(List<Appointment> fullList, Date date,
|
||||
int days) {
|
||||
ArrayList<Appointment> group = new ArrayList<Appointment>();
|
||||
Date startDate = (Date) date.clone();
|
||||
DateUtils.resetTime(startDate);
|
||||
Date endDate = DateUtils.shiftDate(date, days);
|
||||
|
||||
for (Appointment appointment : fullList) {
|
||||
if ((appointment.isMultiDay() || appointment.isAllDay())
|
||||
&& rangeContains(appointment, startDate, endDate)) {
|
||||
group.add(appointment);
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static boolean rangeContains(Appointment appt, Date date) {
|
||||
Date rangeEnd = (Date) date.clone();
|
||||
rangeEnd.setDate(rangeEnd.getDate() + 1);
|
||||
DateUtils.resetTime(rangeEnd);
|
||||
return rangeContains(appt, date, rangeEnd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the specified <code>appointment</code> falls within the
|
||||
* date range defined by <code>rangeStart</code> and <code>rangeEnd</code>.
|
||||
*
|
||||
* @param appointment The appointment to test
|
||||
* @param rangeStart The range lower limit
|
||||
* @param rangeEnd The range upper limit
|
||||
* @return <code>true</code> if the appointment's date falls within the
|
||||
* range, <code>false</code> otherwise.
|
||||
*/
|
||||
public static boolean rangeContains(Appointment appointment,
|
||||
Date rangeStart, Date rangeEnd) {
|
||||
long apptStartMillis = appointment.getStart().getTime();
|
||||
long apptEndMillis = appointment.getEnd().getTime();
|
||||
long rangeStartMillis = rangeStart.getTime();
|
||||
long rangeEndMillis = rangeEnd.getTime();
|
||||
|
||||
return apptStartMillis >= rangeStartMillis
|
||||
&& apptStartMillis < rangeEndMillis
|
||||
|| apptStartMillis <= rangeStartMillis
|
||||
&& apptEndMillis >= rangeStartMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters a list of appointments and returns only appointments with a start
|
||||
* date equal to the date provided. FYI - I hate everything about this
|
||||
* method and am pissed off I have to use it. May be able to avoid it in the
|
||||
* future
|
||||
*
|
||||
* @param fullList A full set of <code>Appointment</code>s, that will be filtered
|
||||
* with the above described rule
|
||||
* @param startDate The start date
|
||||
* @return A list with all appointments whose start date is on or after the
|
||||
* passed <code>startDate</code>
|
||||
*/
|
||||
public static List<Appointment> filterListByDate(List<Appointment> fullList, Date startDate, Date endDate) {
|
||||
|
||||
ArrayList<Appointment> group = new ArrayList<Appointment>();
|
||||
|
||||
for (Appointment appointment : fullList) {
|
||||
if (!appointment.isMultiDay() && !appointment.isAllDay() &&
|
||||
appointment.getEnd().before(endDate)) {
|
||||
//TODO: probably can shorten this by using the compareTo method
|
||||
if (appointment.getStart().after(startDate) ||
|
||||
appointment.getStart().equals(startDate)) {
|
||||
group.add(appointment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.util;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.util.impl.FormattingImpl;
|
||||
import com.google.gwt.core.client.GWT;
|
||||
|
||||
/**
|
||||
* This utility provides access to data to help format widgets
|
||||
* correctly across browsers.
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class FormattingUtil {
|
||||
|
||||
/**
|
||||
* Implementation of formatting class. Holds browser-specific
|
||||
* values, loaded by GWT deferred binding.
|
||||
*/
|
||||
private static FormattingImpl impl = GWT.create(FormattingImpl.class);
|
||||
|
||||
/**
|
||||
* All CSS2 compliant browsers count the border height in the
|
||||
* overall height of an Element. This method returns an offset
|
||||
* value that should be added to the height or width of an item
|
||||
* before setting its size. This will ensure consistent sizing
|
||||
* across compliant and non-compliant browsers.
|
||||
* @return
|
||||
*/
|
||||
public static int getBorderOffset() {
|
||||
return impl.getBorderOffset();
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.util;
|
||||
|
||||
import com.google.gwt.user.client.Window.Navigator;
|
||||
|
||||
/**
|
||||
* Provides a set of re-usable methods related to the client's
|
||||
* browser window.
|
||||
*
|
||||
* @author Brad Rydzewski
|
||||
*/
|
||||
public class WindowUtils {
|
||||
|
||||
/**
|
||||
* Width in pixels of Client's scroll bar.
|
||||
*/
|
||||
private static int scrollBarWidth;
|
||||
|
||||
/**
|
||||
* Gets the width of the client's scroll bar.
|
||||
*
|
||||
* @param useCachedValue Indicates if cached value should be used, or refreshed.
|
||||
* @return Width, in pixels, of Client's scroll bar
|
||||
*/
|
||||
public static int getScrollBarWidth(boolean useCachedValue) {
|
||||
/*
|
||||
* OSX Lion doesn't show the scrollbars (ala iOS) which causes cosmetic problems: issue 143
|
||||
*/
|
||||
boolean isOSXLion = Navigator.getUserAgent().contains("Mac OS X 10.7") || Navigator.getUserAgent().contains("Mac OS X 10_7");
|
||||
if (isOSXLion && Navigator.getUserAgent().contains("Safari")) {
|
||||
// 0 seems to cause weird effects in Chrome
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (useCachedValue && scrollBarWidth > 0) {
|
||||
return scrollBarWidth;
|
||||
}
|
||||
|
||||
/* sometimes getScrollBarWidth() temporarily returns a negative
|
||||
* number. So when this happens we will return "17"
|
||||
* which seems to be default on many systems...
|
||||
* but we won't save it as a cached value.
|
||||
*/
|
||||
int tmpScrollBarWidth = getScrollBarWidth();
|
||||
if (tmpScrollBarWidth <= 0) {
|
||||
return 17;
|
||||
}
|
||||
|
||||
scrollBarWidth = tmpScrollBarWidth;
|
||||
|
||||
return scrollBarWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the width of the clients scroll bar, which can vary among operating systems,
|
||||
* browsers and themes. Based on code from: http://www.alexandre-gomes.com/?p=115
|
||||
*
|
||||
* @return The width of the browser scrollbar in pixels
|
||||
*/
|
||||
private static native int getScrollBarWidth() /*-{
|
||||
|
||||
var inner = document.createElement("p");
|
||||
inner.style.width = "100%";
|
||||
inner.style.height = "200px";
|
||||
|
||||
var outer = document.createElement("div");
|
||||
outer.style.position = "absolute";
|
||||
outer.style.top = "0px";
|
||||
outer.style.left = "0px";
|
||||
outer.style.visibility = "hidden";
|
||||
outer.style.width = "200px";
|
||||
outer.style.height = "150px";
|
||||
outer.style.overflow = "hidden";
|
||||
outer.appendChild (inner);
|
||||
|
||||
document.body.appendChild (outer);
|
||||
var w1 = inner.offsetWidth;
|
||||
outer.style.overflow = "scroll";
|
||||
var w2 = inner.offsetWidth;
|
||||
if (w1 == w2) w2 = outer.clientWidth;
|
||||
|
||||
document.body.removeChild (outer);
|
||||
|
||||
return (w1 - w2);
|
||||
}-*/;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.util.impl;
|
||||
|
||||
public class FormattingIE6Impl extends FormattingImpl {
|
||||
|
||||
@Override
|
||||
public int getBorderOffset() {
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package com.bradrydzewski.gwt.calendar.client.util.impl;
|
||||
|
||||
public class FormattingImpl {
|
||||
|
||||
public int getBorderOffset() {
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
<module>
|
||||
<stylesheet src="gwt-cal-google.css"/>
|
||||
<!-- <replace-with class="com.bradrydzewski.gwt.calendar.theme.google.client.GoogleAppointmentTheme">-->
|
||||
<!-- <when-type-is class="com.bradrydzewski.gwt.calendar.client.AppointmentTheme"/>-->
|
||||
<!-- </replace-with>-->
|
||||
<replace-with class="com.bradrydzewski.gwt.calendar.theme.google.client.GoogleMonthViewStyleManager">
|
||||
<when-type-is class="com.bradrydzewski.gwt.calendar.client.monthview.MonthViewStyleManager"/>
|
||||
</replace-with>
|
||||
<replace-with class="com.bradrydzewski.gwt.calendar.theme.google.client.GoogleDayViewStyleManager">
|
||||
<when-type-is class="com.bradrydzewski.gwt.calendar.client.dayview.DayViewStyleManager"/>
|
||||
</replace-with>
|
||||
<replace-with class="com.bradrydzewski.gwt.calendar.theme.google.client.GoogleTechViewStyleManager">
|
||||
<when-type-is class="com.bradrydzewski.gwt.calendar.client.techview.TechViewStyleManager"/>
|
||||
</replace-with>
|
||||
</module>
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* This file is part of gwt-cal
|
||||
* Copyright (C) 2011 Scottsdale Software LLC
|
||||
*
|
||||
* gwt-cal is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/
|
||||
*/
|
||||
|
||||
package com.bradrydzewski.gwt.calendar.theme.google.client;
|
||||
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.ThemeAppointmentStyle;
|
||||
|
||||
class GoogleAppointmentStyle implements ThemeAppointmentStyle {
|
||||
|
||||
public GoogleAppointmentStyle(String border, String background) {
|
||||
super();
|
||||
|
||||
//set the border
|
||||
this.border = background;
|
||||
this.selectedBorder = border;
|
||||
|
||||
//set the body text
|
||||
this.text = "#FFFFFF";
|
||||
this.selectedText = text;
|
||||
|
||||
//set the header text
|
||||
this.headerText = text;
|
||||
this.selectedHeaderText = text;
|
||||
|
||||
//set the background colors
|
||||
this.background = background;
|
||||
this.selectedBackground = background;
|
||||
|
||||
//set the header colors to the same color as the border
|
||||
this.backgroundHeader = border;
|
||||
this.selectedBackgroundHeader = border;
|
||||
|
||||
}
|
||||
|
||||
protected String selectedBorder;
|
||||
protected String selectedBackground;
|
||||
protected String selectedBackgroundImage;
|
||||
protected String selectedBackgroundHeader;
|
||||
protected String selectedBackgroundFooter;
|
||||
protected String selectedText;
|
||||
protected String selectedHeaderText;
|
||||
protected String border;
|
||||
protected String background;
|
||||
protected String backgroundImage;
|
||||
protected String backgroundHeader;
|
||||
protected String backgroundFooter;
|
||||
protected String text;
|
||||
protected String headerText;
|
||||
|
||||
public String getSelectedBorder() {
|
||||
return selectedBorder;
|
||||
}
|
||||
|
||||
public String getSelectedBackground() {
|
||||
return selectedBackground;
|
||||
}
|
||||
|
||||
public String getSelectedBackgroundHeader() {
|
||||
return selectedBackgroundHeader;
|
||||
}
|
||||
|
||||
public String getSelectedBackgroundFooter() {
|
||||
return selectedBackgroundFooter;
|
||||
}
|
||||
|
||||
public String getSelectedText() {
|
||||
return selectedText;
|
||||
}
|
||||
|
||||
public String getSelectedHeaderText() {
|
||||
return selectedHeaderText;
|
||||
}
|
||||
|
||||
public String getBorder() {
|
||||
return border;
|
||||
}
|
||||
|
||||
public String getBackground() {
|
||||
return background;
|
||||
}
|
||||
|
||||
public String getBackgroundHeader() {
|
||||
return backgroundHeader;
|
||||
}
|
||||
|
||||
public String getBackgroundFooter() {
|
||||
return backgroundFooter;
|
||||
}
|
||||
|
||||
public String getText() {
|
||||
return text;
|
||||
}
|
||||
|
||||
public String getHeaderText() {
|
||||
return headerText;
|
||||
}
|
||||
|
||||
public void setSelectedBorder(String selectedBorder) {
|
||||
this.selectedBorder = selectedBorder;
|
||||
}
|
||||
|
||||
public void setSelectedBackground(String selectedBackground) {
|
||||
this.selectedBackground = selectedBackground;
|
||||
}
|
||||
|
||||
public void setSelectedBackgroundHeader(String selectedBackgroundHeader) {
|
||||
this.selectedBackgroundHeader = selectedBackgroundHeader;
|
||||
}
|
||||
|
||||
public void setSelectedBackgroundFooter(String selectedBackgroundFooter) {
|
||||
this.selectedBackgroundFooter = selectedBackgroundFooter;
|
||||
}
|
||||
|
||||
public void setSelectedText(String selectedText) {
|
||||
this.selectedText = selectedText;
|
||||
}
|
||||
|
||||
public void setSelectedHeaderText(String selectedHeaderText) {
|
||||
this.selectedHeaderText = selectedHeaderText;
|
||||
}
|
||||
|
||||
public void setBorder(String border) {
|
||||
this.border = border;
|
||||
}
|
||||
|
||||
public void setBackground(String background) {
|
||||
this.background = background;
|
||||
}
|
||||
|
||||
public void setBackgroundHeader(String backgroundHeader) {
|
||||
this.backgroundHeader = backgroundHeader;
|
||||
}
|
||||
|
||||
public void setBackgroundFooter(String backgroundFooter) {
|
||||
this.backgroundFooter = backgroundFooter;
|
||||
}
|
||||
|
||||
public void setText(String text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public void setHeaderText(String headerText) {
|
||||
this.headerText = headerText;
|
||||
}
|
||||
|
||||
public String getSelectedBackgroundImage() {
|
||||
return selectedBackgroundImage;
|
||||
}
|
||||
|
||||
public String getBackgroundImage() {
|
||||
return backgroundImage;
|
||||
}
|
||||
|
||||
public void setSelectedBackgroundImage(String selectedBackgroundImage) {
|
||||
this.selectedBackgroundImage = selectedBackgroundImage;
|
||||
}
|
||||
|
||||
public void setBackgroundImage(String backgroundImage) {
|
||||
this.backgroundImage = backgroundImage;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package com.bradrydzewski.gwt.calendar.theme.google.client;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.bradrydzewski.gwt.calendar.client.AppointmentStyle;
|
||||
|
||||
final public class GoogleAppointmentTheme {
|
||||
//border, background
|
||||
public static final GoogleAppointmentStyle BLUE = new GoogleAppointmentStyle("#2952A3", "#668CD9");
|
||||
public static final GoogleAppointmentStyle RED = new GoogleAppointmentStyle("#A32929", "#D96666");
|
||||
public static final GoogleAppointmentStyle PINK = new GoogleAppointmentStyle("#B1365F", "#E67399");
|
||||
public static final GoogleAppointmentStyle PURPLE = new GoogleAppointmentStyle("#7A367A", "#B373B3");
|
||||
public static final GoogleAppointmentStyle DARK_PURPLE = new GoogleAppointmentStyle("#5229A3", "#8C66D9");
|
||||
public static final GoogleAppointmentStyle STEELE_BLUE = new GoogleAppointmentStyle("#29527A", "#29527A");
|
||||
public static final GoogleAppointmentStyle LIGHT_BLUE = new GoogleAppointmentStyle("#1B887A", "#59BFB3");
|
||||
public static final GoogleAppointmentStyle TEAL = new GoogleAppointmentStyle("#28754E", "#65AD89");
|
||||
public static final GoogleAppointmentStyle LIGHT_TEAL = new GoogleAppointmentStyle("#4A716C", "#85AAA5");
|
||||
public static final GoogleAppointmentStyle GREEN = new GoogleAppointmentStyle("#0D7813", "#4CB052");
|
||||
public static final GoogleAppointmentStyle LIGHT_GREEN = new GoogleAppointmentStyle("#528800", "#8CBF40");
|
||||
public static final GoogleAppointmentStyle YELLOW_GREEN = new GoogleAppointmentStyle("#88880E", "#BFBF4D");
|
||||
public static final GoogleAppointmentStyle YELLOW = new GoogleAppointmentStyle("#AB8B00", "#E0C240");
|
||||
public static final GoogleAppointmentStyle ORANGE = new GoogleAppointmentStyle("#BE6D00", "#F2A640");
|
||||
public static final GoogleAppointmentStyle RED_ORANGE = new GoogleAppointmentStyle("#B1440E", "#E6804D");
|
||||
public static final GoogleAppointmentStyle LIGHT_BROWN = new GoogleAppointmentStyle("#865A5A", "#BE9494");
|
||||
public static final GoogleAppointmentStyle LIGHT_PURPLE = new GoogleAppointmentStyle("#705770", "#A992A9");
|
||||
public static final GoogleAppointmentStyle GREY = new GoogleAppointmentStyle("#4E5D6C", "#8997A5");
|
||||
public static final GoogleAppointmentStyle BLUE_GREY = new GoogleAppointmentStyle("#5A6986", "#94A2bE");
|
||||
public static final GoogleAppointmentStyle YELLOW_GREY = new GoogleAppointmentStyle("#6E6E41", "#A7A77D");
|
||||
public static final GoogleAppointmentStyle BROWN = new GoogleAppointmentStyle("#8D6F47", "#C4A883");
|
||||
public static final GoogleAppointmentStyle DEFAULT = BLUE;
|
||||
public static final Map<AppointmentStyle, GoogleAppointmentStyle> STYLES = new HashMap<AppointmentStyle, GoogleAppointmentStyle>();
|
||||
|
||||
static {
|
||||
STYLES.put(AppointmentStyle.BLUE, BLUE);
|
||||
STYLES.put(AppointmentStyle.BLUE_GREY, BLUE_GREY);
|
||||
STYLES.put(AppointmentStyle.BROWN, BROWN);
|
||||
STYLES.put(AppointmentStyle.DARK_PURPLE, DARK_PURPLE);
|
||||
STYLES.put(AppointmentStyle.GREEN, GREEN);
|
||||
STYLES.put(AppointmentStyle.GREY, GREY);
|
||||
STYLES.put(AppointmentStyle.LIGHT_BLUE, LIGHT_BLUE);
|
||||
STYLES.put(AppointmentStyle.LIGHT_BROWN, LIGHT_BROWN);
|
||||
STYLES.put(AppointmentStyle.LIGHT_GREEN, LIGHT_GREEN);
|
||||
STYLES.put(AppointmentStyle.LIGHT_PURPLE, LIGHT_PURPLE);
|
||||
STYLES.put(AppointmentStyle.LIGHT_TEAL, LIGHT_TEAL);
|
||||
STYLES.put(AppointmentStyle.ORANGE, ORANGE);
|
||||
STYLES.put(AppointmentStyle.PINK, PINK);
|
||||
STYLES.put(AppointmentStyle.PURPLE, PURPLE);
|
||||
STYLES.put(AppointmentStyle.RED, RED);
|
||||
STYLES.put(AppointmentStyle.RED_ORANGE, RED_ORANGE);
|
||||
STYLES.put(AppointmentStyle.STEELE_BLUE, STEELE_BLUE);
|
||||
STYLES.put(AppointmentStyle.TEAL, TEAL);
|
||||
STYLES.put(AppointmentStyle.YELLOW, YELLOW);
|
||||
STYLES.put(AppointmentStyle.YELLOW_GREEN, YELLOW_GREEN);
|
||||
STYLES.put(AppointmentStyle.YELLOW_GREY, YELLOW_GREY);
|
||||
STYLES.put(AppointmentStyle.DEFAULT, DEFAULT);
|
||||
}
|
||||
|
||||
private GoogleAppointmentTheme() { }
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user