package com.chap.links.client;
import java.util.Date;
import com.chap.links.client.Timeline;
import com.chap.links.client.events.AddHandler;
import com.chap.links.client.events.ChangeHandler;
import com.chap.links.client.events.DeleteHandler;
import com.chap.links.client.events.EditHandler;
import com.chap.links.client.events.TimeChangeHandler;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JsArray;
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.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.Selection;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.events.RangeChangeHandler;
import com.google.gwt.visualization.client.events.SelectHandler;
/**
* TimelineEntryPoint
*
* Entry point classes define <code>onModuleLoad()</code>.
*
* The class TimelineEntryPoint is for test purposes. To run the program, you
* have to open the file Timeline.gwt.xml, and uncomment the line <entry-point
* class='com.chap.links.client.TimelineEntryPoint'/> such that the entry point
* is defined.
*
* If you want to create a stand-alone module for the timeline, you have to
* comment the line with the entry point again, and then create a jar containing
* only Timeline.java, Timeline.gwt.xml, timeline.js, and timeline.css
*/
public class TimelineEntryPoint implements EntryPoint {
final TextBox txtStartDate = new TextBox();
final TextBox txtEndDate = new TextBox();
final Button btnSetRange = new Button("Set");
final Label lblCustomTime = new Label();
final CheckBox chkConfirmChange = new CheckBox("Confirm changes");
final Button btnRedraw = new Button("Redraw");
final Button btnAddData = new Button("Add data");
DataTable data = null;
Timeline.Options options = null;
Timeline timeline = null;
DateTimeFormat dtf = DateTimeFormat.getFormat("yyyy-MM-dd");
/**
* This is the entry point method.
*/
public void onModuleLoad() {
// Create a callback to be called when the visualization API
// has been loaded.
Runnable onLoadCallback = new Runnable() {
public void run() {
RootPanel.get("txtStartDate").add(txtStartDate);
RootPanel.get("txtEndDate").add(txtEndDate);
RootPanel.get("btnSetRange").add(btnSetRange);
RootPanel.get("lblCustomTime").add(lblCustomTime);
RootPanel.get("chkConfirmChange").add(chkConfirmChange);
RootPanel.get("btnRedraw").add(btnRedraw);
btnRedraw.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
timeline.redraw();
}
});
RootPanel.get("btnAddData").add(btnAddData);
btnAddData.addClickHandler(new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
int i = data.getNumberOfRows();
data.addRows(1);
data.setValue(i, 0, dtf.parse("2010-08-23"));
data.setValue(i, 1, dtf.parse("2010-08-30"));
data.setValue(i, 2, "Added");
timeline.setData(data);
timeline.redraw();
}
});
// Add a handler to the add button
btnSetRange.addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
setRange();
}
});
timeline = createTimeline();
RootPanel.get("mytimeline").add(timeline);
getRange();
}
};
// Load the visualization api, passing the onLoadCallback to be called
// when loading is done.
VisualizationUtils.loadVisualizationApi(onLoadCallback);
}
private Timeline createTimeline() {
data = DataTable.create();
data.addColumn(DataTable.ColumnType.DATETIME, "startdate");
data.addColumn(DataTable.ColumnType.DATETIME, "enddate");
data.addColumn(DataTable.ColumnType.STRING, "content");
// fill the table with some data
data.addRows(3);
data.setValue(0, 0, dtf.parse("2012-08-23"));
data.setValue(0, 1, dtf.parse("2012-08-30"));
data.setValue(0, 2, "Conversation");
data.setValue(1, 0, dtf.parse("2012-08-28"));
data.setValue(1, 2, "Memo");
data.setValue(2, 0, dtf.parse("2012-09-02"));
data.setValue(2, 2, "Phone Call");
options = Timeline.Options.create();
options.setStyle(Timeline.Options.STYLE.BOX);
options.setStart(dtf.parse("2012-08-18"));
options.setEnd(dtf.parse("2012-09-10"));
//options.setHeight("200px");
options.setHeight("auto");
options.setWidth("75%");
options.setEditable(true);
options.setShowCustomTime(true);
options.setShowNavigation(true);
// options.setAxisOnTop(true);
// options.setShowMajorLabels(false);
// options.setShowMinorLabels(false);
// options.setScale(SCALE.DAY, 1);
options.setMin(dtf.parse("2012-01-01")); // lower limit of visible range
options.setMax(dtf.parse("2012-12-31")); // upper limit of visible range
options.setZoomMin(1000L * 60L * 60L * 24L); // one day in milliseconds
options.setZoomMax(1000L * 60L * 60L * 24L * 31L * 3L); // about three months in milliseconds
// create the timeline, with data and options
timeline = new Timeline(data, options);
// add event handlers
timeline.addSelectHandler(createSelectHandler(timeline));
timeline.addRangeChangeHandler(createRangeChangeHandler(timeline));
timeline.addChangeHandler(createChangeHandler(timeline));
timeline.addAddHandler(createAddHandler(timeline));
timeline.addEditHandler(createEditHandler(timeline));
timeline.addDeleteHandler(createDeleteHandler(timeline));
timeline.addTimeChangeHandler(createTimeChangeHandler(timeline));
// timeline.setScale(SCALE.DAY, 1); // TODO: gives problems!
return timeline;
}
/**
* Get the range from the timeline and put it in the textboxes on screen
*/
private void getRange() {
Timeline.DateRange range = timeline.getVisibleChartRange();
DateTimeFormat dtf = DateTimeFormat.getFormat("yyyy-MM-dd HH:mm:ss");
// set the new startdate and enddate
txtStartDate.setText(dtf.format(range.getStart()));
txtEndDate.setText(dtf.format(range.getEnd()));
}
/**
* Get the entered dates from the textboxes on screen, and apply them to the
* timeline
*/
private void setRange() {
DateTimeFormat datetime = DateTimeFormat
.getFormat("yyyy-MM-dd HH:mm:ss");
DateTimeFormat date = DateTimeFormat.getFormat("yyyy-MM-dd");
Date startDate;
Date endDate;
// Try to parse the startdate
try {
startDate = datetime.parse(txtStartDate.getText());
} catch (IllegalArgumentException err) {
try {
startDate = date.parse(txtStartDate.getText());
} catch (IllegalArgumentException err2) {
Window
.alert("I don't understand the startdate that you entered :(");
return;
}
}
// Try to parse the enddate
try {
endDate = datetime.parse(txtEndDate.getText());
} catch (IllegalArgumentException err) {
try {
endDate = date.parse(txtEndDate.getText());
} catch (IllegalArgumentException err2) {
Window
.alert("I cannot make sense of the enddate that you entered :(");
return;
}
}
timeline.setVisibleChartRange(startDate, endDate);
timeline.redraw();
}
/**
* add a select handler (the select event occurs when the user clicks on an
* event)
*
* @param timeline
* @return
*/
private SelectHandler createSelectHandler(final Timeline timeline) {
return new SelectHandler() {
@Override
public void onSelect(SelectEvent event) {
JsArray<Selection> sel = timeline.getSelections();
if (sel.length() > 0) {
int row = sel.get(0).getRow();
String info = "Select event " + String.valueOf(row)
+ " selected";
RootPanel.get("lblInfo").add(new Label(info));
} else {
String info = "Select event <nothing> selected";
RootPanel.get("lblInfo").add(new Label(info));
}
}
};
}
/**
* create a RangeChange handler (this event occurs when the user changes the
* visible range by moving or scrolling the Timeline).
*
* @param timeline
* @return
*/
private RangeChangeHandler createRangeChangeHandler(final Timeline timeline) {
return new RangeChangeHandler() {
@Override
public void onRangeChange(RangeChangeEvent event) {
getRange();
}
};
}
/**
* create a change handler (this event occurs when the user changes the
* position of an event by dragging it).
*
* @param timeline
* @return
*/
private ChangeHandler createChangeHandler(final Timeline timeline) {
return new ChangeHandler() {
@Override
public void onChange(ChangeEvent event) {
// retrieve the row number of the changed event
JsArray<Selection> sel = timeline.getSelections();
if (sel.length() > 0) {
int row = sel.get(0).getRow();
boolean confirmChanges = chkConfirmChange.getValue();
// request confirmation
boolean applyChange = confirmChanges ? Window
.confirm("Are you sure you want to change this event?")
: true;
if (applyChange) {
String info = "Change event " + String.valueOf(row)
+ " changed";
RootPanel.get("lblInfo").add(new Label(info));
} else {
timeline.cancelChange();
String info = "Change event " + String.valueOf(row)
+ " cancelled";
RootPanel.get("lblInfo").add(new Label(info));
}
}
}
};
}
/**
* create an add handler (this event occurs when the user creates a new
* event).
*
* @param timeline
* @return
*/
private AddHandler createAddHandler(final Timeline timeline) {
return new AddHandler() {
@Override
public void onAdd(AddEvent event) {
// retrieve the row number of the changed event
JsArray<Selection> sel = timeline.getSelections();
if (sel.length() > 0) {
int row = sel.get(0).getRow();
// request confirmation
String title = Window.prompt(
"Enter a title for the new event", "New event");
if (title != null) {
// apply the new title
data.setValue(row, 2, title);
String info = "Add event " + String.valueOf(row)
+ " applied";
RootPanel.get("lblInfo").add(new Label(info));
} else {
// cancel creating new event
timeline.cancelAdd();
String info = "Add event " + String.valueOf(row)
+ " cancelled";
RootPanel.get("lblInfo").add(new Label(info));
}
}
}
};
}
/**
* create a time change handler (this event occurs when the user draggs
* the custom time bar).
*
* @param timeline
* @return
*/
private TimeChangeHandler createTimeChangeHandler(final Timeline timeline) {
return new TimeChangeHandler() {
@Override
public void onTimeChange(TimeChangeEvent event) {
Date time = event.getTime();
lblCustomTime.setText(time.toString());
}
};
}
/**
* create an edit handler (this event occurs when the user double clicks
* an event).
*
* @param timeline
* @return
*/
private EditHandler createEditHandler(final Timeline timeline) {
return new EditHandler() {
@Override
public void onEdit(EditEvent event) {
// retrieve the row number of the changed event
JsArray<Selection> sel = timeline.getSelections();
if (sel.length() > 0) {
int row = sel.get(0).getRow();
// request confirmation
String title = Window.prompt(
"Enter a new title",
data.getValueString(row, 2));
if (title != null) {
// apply the new title
data.setValue(row, 2, title);
String info = "Edit event " + String.valueOf(row)
+ " applied";
RootPanel.get("lblInfo").add(new Label(info));
} else {
// edit nothing
String info = "Edit event " + String.valueOf(row)
+ " cancelled";
RootPanel.get("lblInfo").add(new Label(info));
}
}
}
};
}
/**
* create a delete handler (this event occurs when the user clicks the
* delete button on the top right of an event).
*
* @param timeline
* @return
*/
private DeleteHandler createDeleteHandler(final Timeline timeline) {
return new DeleteHandler() {
@Override
public void onDelete(DeleteEvent event) {
// retrieve the row number of the changed event
JsArray<Selection> sel = timeline.getSelections();
if (sel.length() > 0) {
int row = sel.get(0).getRow();
boolean confirmChanges = chkConfirmChange.getValue();
// request confirmation
boolean applyDelete = confirmChanges ? Window
.confirm("Are you sure you want to delete this event?")
: true;
if (applyDelete) {
String info = "Deleted event " + String.valueOf(row);
RootPanel.get("lblInfo").add(new Label(info));
} else {
timeline.cancelDelete();
String info = "Delete event " + String.valueOf(row)
+ " cancelled";
RootPanel.get("lblInfo").add(new Label(info));
}
}
}
};
}
}