[Tynstep-svn] r32 - in trunk: StepDataLoader/sql/com/tyndalehouse/step/dataloader/sql/create StepDataLoader/src/com/tyndalehouse/step/dataloader StepDataLoader/src/com/tyndalehouse/step/dataloader/beans StepDataLoader/src/com/tyndalehouse/step/dataloader/loaders step-web-app/src/main/java/com/tyndalehouse/step/web/client step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter step-web-app/src/main/java/com/tyndalehouse/step/web/client/timeline step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/events step-web-app/src/main/java/com/tyndalehouse/step/web/client/view step-web-app/src/main/java/com/tyndalehouse/step/web/client/widgets step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command step-web-app/src/main/java/com/tyndalehouse/step/web/shared/event step-web-app/src/main/java/com/tyndalehouse/step/web/shared/eventhandler step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result step-web-app/war/css

ChrisBurrell at crosswire.org ChrisBurrell at crosswire.org
Mon Dec 7 15:47:44 MST 2009


Author: ChrisBurrell
Date: 2009-12-07 15:47:44 -0700 (Mon, 07 Dec 2009)
New Revision: 32

Added:
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/CannotDeleteEventException.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/IncapableOfCalculatingRequestWindowException.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/RequestWindow.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeConversionUtil.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeScale.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimebandRequestWindow.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/events/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/events/TimelineMouseHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimeBandVisibleDate.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/event/TimelineScrollEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/eventhandler/TimelineScrollEventHandler.java
Removed:
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/timeline/data/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/ScaleBand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/ScrollListener.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimelineMouseHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/widgets/timeline/
Modified:
   trunk/StepDataLoader/sql/com/tyndalehouse/step/dataloader/sql/create/3.timeline.sql
   trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/Dataloader.java
   trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/beans/TimelineBean.java
   trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/beans/TimelineEventBean.java
   trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/loaders/TimelineLoader.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/CachingDispatchAsync.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/TimelinePresenter.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeBand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/Timeline.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/TimelineView.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetEventsForDateRangeHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineUISetupHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimelineBean.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimelineEventBean.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetEventsForDateRangeCommand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetEventsForDateRangeResult.java
   trunk/step-web-app/war/css/step.css
Log:
timeline widget updates. now on to the zoom functionality, which is half working. minor bugs with the timescale's dates not being repainted properly

Modified: trunk/StepDataLoader/sql/com/tyndalehouse/step/dataloader/sql/create/3.timeline.sql
===================================================================
--- trunk/StepDataLoader/sql/com/tyndalehouse/step/dataloader/sql/create/3.timeline.sql	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/StepDataLoader/sql/com/tyndalehouse/step/dataloader/sql/create/3.timeline.sql	2009-12-07 22:47:44 UTC (rev 32)
@@ -2,23 +2,36 @@
 
 call dropIfExists('alternative_date');
 call dropIfExists('event');
-call dropIfExists('timeline');
+call dropIfExists('timeband');
+call dropIfExists('sub_timeband');
 call dropIfExists('event_type');
 
 /**
  * Timeline table indicating different types of timelines.
  */
-create table timeline (
-	timeline_id 				int PRIMARY KEY,
-	timeline_description		varchar(50),			-- TODO: this should probably be made an ID to timeline_description
+create table timeband (
+	timeband_id 				int PRIMARY KEY,
+	timeband_description		varchar(50),			-- TODO: this should probably be made an ID to timeline_description
 														-- table, so that we can localise, or remove this
 														-- and localise in the java layer...
-	timeline_code				varchar(50)
+	timeband_code				varchar(50)
 );
 
 /**
  * Timeline table indicating different types of timelines.
  */
+create table sub_timeband (
+	sub_timeband_id 				int PRIMARY KEY,
+	sub_timeband_description		varchar(50),			-- TODO: this should probably be made an ID to timeline_description
+														-- table, so that we can localise, or remove this
+														-- and localise in the java layer...
+	sub_timeband_code				varchar(50)
+);
+
+
+/**
+ * Timeline table indicating different types of timelines.
+ */
 create table event_type (
 	event_type_id 			int PRIMARY KEY,
 	event_description		varchar(50),			
@@ -37,8 +50,9 @@
 	to_date 					bigint,			-- nullable, may a point in time.
 	from_precision 				char(1), 		-- D/M/Y:: D=> take the whole date, M=>only month and year, Y=>only year is relevant
 	to_precision				char(1),
-	timeline_id 				int CONSTRAINT timeline_id_fk REFERENCES timeline (timeline_id),	
-	importance_id 				int CONSTRAINT importance_id_fk REFERENCES timeline (timeline_id),
+	timeband_id					int CONSTRAINT timeband_id_fk REFERENCES timeband (timeband_id),
+	sub_timeband_id 			int CONSTRAINT sub_timeband_id_fk REFERENCES sub_timeband (sub_timeband_id),	
+	importance_id 				int CONSTRAINT importance_id_fk REFERENCES sub_timeband (sub_timeband_id),
 	certainty 					varchar(25),	
 	flags 						varchar(50),
 	event_type_id				int CONSTRAINT event_type_id_fk REFERENCES event_type(event_type_id),
@@ -60,6 +74,8 @@
 -- finally create indexes:
 -- do some performance tests - it may be that full table scans might be better.
 -- TODO: these are just guesses at the moment!
-create index timeline_id_ind on event(timeline_id);
+-- can't remember if we need to created indexes on foreign keys in javaDB
+create index timeband_id_ind on event(timeband_id);
+create index sub_timeband_id_ind on event(sub_timeband_id);
 create index from_date_from_precision_ind on event(from_date, from_precision);
 create index to_date_to_precision_ind on event(from_date, from_precision);

Modified: trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/Dataloader.java
===================================================================
--- trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/Dataloader.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/Dataloader.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -17,84 +17,12 @@
 import com.tyndalehouse.step.dataloader.loaders.TimelineLoader;
 
 public class Dataloader {
-	
-	//check whether the .40 at the end means verse or chapter
-	//String reference = "2Sam.5.1-5; 1Chr.11.1-3; 1Chr.11.10-12.40";
-	// 2nd example: Matt.4.18-24;Matt.8.2-4;Matt.8.14-17;Matt.9.1-17;Mark.1.16-2.22;Luke.4.31-5.39
-	//could do a regular expression maybe? but would have to name the groups,
-	//and how do names work if they are repeated etc...
-	//performance comparison would be necessary.
-	
-	//TODO: assess performance, and perhaps need to change data tier
-	//to reflect this. 
-	//choice is to input each verse number according to what JSword
-	//returns to us...
-	private static void parseReference(final String reference) throws NoSuchKeyException {
-		//TODO: assess performance of this function...
-		
-		
-		
-		
-		
-		
-		//		RocketPassage p1 = new RocketPassage();
-//		VerseRange r1 = p1.getRangeAt(0, RestrictionType.NONE);
-//		
-		
-		
-		String[] multiRef = reference.replace(" ", "").split(";");
-		
-		
-//		
-//		String[] ss = p.split(reference);
-//		for(String s : ss) {
-//			System.out.println("s:" + s);
-//		}
-//		
-//		
-		//[A-Za-z]+\.[0-9]+(\.[0-9])?-([0-9]+(\.[0-9])?
-		
-//		
-//		//each multiRef item contains one scripture reference...
-//		for(String r : multiRef) {
-//			//the first dot will be the end of the book
-//			int indexOfFirstDot = r.indexOf('.');
-//			int indexOfDash = r.indexOf('-');
-//			String bookName = r.substring(0, indexOfFirstDot);
-//			
-//			//2ndly we are concerned with the -, since as far as I can see there should
-//			//only be 1 -
-//			//TODO: check against spec!
-//			String refStart = r.substring(indexOfFirstDot + 1, indexOfDash);
-//			String refEnd =   r.substring(indexOfDash + 1);
-//			
-//			//now we have refStart and refEnd in the following format:
-//			// 12(.34)?
-//			//if we have a dot, we assume we have chapter and verse,
-//			//if not, we assume we have 
-//			
-//			
-//			System.out.println("b: " + bookName);
-//			System.out.println("s: " + refStart);
-//			System.out.println("e: " + refEnd);
-//			
-//		}
-		
-	}
-	
 	public static void main(String args[]) throws SQLException, ClassNotFoundException, IOException, DateParsingException, NoSuchKeyException {
 		if(System.getProperty("driver") != null) {
 			DbUtils.loadDriver(System.getProperty("org.apache.derby.jdbc.ClientDriver"));
 		} else {
 			DbUtils.loadDriver("org.apache.derby.jdbc.EmbeddedDriver");	
 		}
-		
-		String reference = "2Sam.5.1-5; 1Chr.11.1-3; 1Chr.11.10-12.40";
-//		parseReference(reference);
-		
-		
-		
-	//	if(true) return;
 	
 		SchemaLoader sl = new SchemaLoader();
 		TimelineLoader tl = new TimelineLoader();
@@ -112,5 +40,4 @@
 			
 	}
 
-	
 }

Modified: trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/beans/TimelineBean.java
===================================================================
--- trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/beans/TimelineBean.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/beans/TimelineBean.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -39,7 +39,7 @@
 
 	public String getInsertStatement() {
 		StringBuffer statement = new StringBuffer();
-		statement.append("insert into step.timeline(timeline_id, timeline_code, timeline_description) values(")
+		statement.append("insert into step.timeband(timeband_id, timeband_code, timeband_description) values(")
 			.append(getTimelineId())
 			.append(", ")
 			.append(getDbString(getTimelineCode()))			
@@ -49,6 +49,23 @@
 		
 		return statement.toString();
 	}
+
+	/**
+	 * TODO: this is a bit hacky. make it with the own POJO
+	 * @return
+	 */
+	public String getSubTimebandInsertStatement() {
+		StringBuffer statement = new StringBuffer();
+		statement.append("insert into step.sub_timeband(sub_timeband_id, sub_timeband_code, sub_timeband_description) values(")
+			.append(getTimelineId())
+			.append(", ")
+			.append(getDbString(getTimelineCode()))			
+			.append(", ")
+			.append(getDbString(getTimelineDescription()))
+			.append(");");
+		
+		return statement.toString();
+	}
 }
 
 

Modified: trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/beans/TimelineEventBean.java
===================================================================
--- trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/beans/TimelineEventBean.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/beans/TimelineEventBean.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -18,15 +18,16 @@
 	private String refs;
 	private String source;
 	private String notes;
+	private String timebandId;
 
 	private static final String alternativeDateInsertStatement = "insert into step.alternative_date" +
 			"(event_id, from_date, to_date, from_date_precision, to_date_precision) values" +
 			"(?,?,?,?,?)";
 	
 	private static final String eventInsert = "insert into step.event(" +
-		"event_id, event_text_id, name, from_date, to_date, from_precision, to_precision, timeline_id, importance_id, certainty, " +
+		"event_id, event_text_id, name, from_date, to_date, from_precision, to_precision, timeband_id, sub_timeband_id, importance_id, certainty, " +
 		"flags, event_type_id, description, source, notes) values(" +
-		"?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
+		"?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
 	
 	private static final String scriptureReferenceInsertStatement = "insert into scripture_reference(" +
 			"target_id, target_type, start_verse_id, end_verse_id) values (?, ?, ?, ?)";
@@ -229,8 +230,26 @@
 
 
 
+	/**
+	 * @return the timeband_id
+	 */
+	public String getTimebandId() {
+		return timebandId;
+	}
 
 
+
+
+
+	/**
+	 * @param timebandId the timeband_id to set
+	 */
+	public void setTimebandId(String timebandId) {
+		this.timebandId = timebandId;
+	}
+
+
+
 	public static String getAlternativeDateStatement() {
 		return alternativeDateInsertStatement;
 	}

Modified: trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/loaders/TimelineLoader.java
===================================================================
--- trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/loaders/TimelineLoader.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/StepDataLoader/src/com/tyndalehouse/step/dataloader/loaders/TimelineLoader.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -33,7 +33,8 @@
 import com.tyndalehouse.step.dataloader.common.DateParsingException;
 
 public class TimelineLoader extends AbstractLoader {
-	private HashMap<String, TimelineBean> timelines;
+	private HashMap<String, TimelineBean> subTimebands;
+	private HashMap<String, TimelineBean> timebands;
 	private HashMap<String, EventTypeBean> eventTypes;
 
 	public TimelineLoader() throws SQLException {
@@ -69,6 +70,7 @@
 			}
 		});
 
+		//TODO: change timeband_id to sub_timeband_id and timeband_id = filename
 		List<TimelineEventBean> events = new ArrayList<TimelineEventBean>();
 		TimelineEventBean tb;
 		int count = 0;
@@ -81,6 +83,8 @@
 			final String[] header = inFile.getCSVHeader(true);
 			// add processors to aid conversion?
 			while ((tb = inFile.read(TimelineEventBean.class, header)) != null) {
+				//chop off the extension of the file
+				tb.setTimebandId(f.getName().substring(0, f.getName().length()-4)); 
 				events.add(tb);
 				count++;
 			}
@@ -94,16 +98,30 @@
 	 * Adds the timeline to the hashmap passed in, assuming it is not already in
 	 * there This is just a helper function really
 	 * 
+	 * @param subTimebandCode
+	 */
+	public void addSubTimebandIfNotExists(final String subTimebandCode) {
+		if (!subTimebands.containsKey(subTimebandCode)) {
+			// debatable as to whether or not we want to set the id here...
+			TimelineBean tb = new TimelineBean(subTimebands.size() + 1, subTimebandCode, subTimebandCode);
+			subTimebands.put(subTimebandCode, tb);
+		}
+	}
+
+	/**
+	 * Adds the timeline to the hashmap passed in, assuming it is not already in
+	 * there This is just a helper function really
+	 * 
 	 * @param timelineCode
 	 */
-	public void addTimelineIfNotExists(final String timelineCode) {
-		if (!timelines.containsKey(timelineCode)) {
+	public void addTimebandIfNotExists(final String timelineCode) {
+		if (!timebands.containsKey(timelineCode)) {
 			// debatable as to whether or not we want to set the id here...
-			TimelineBean tb = new TimelineBean(timelines.size() + 1, timelineCode, timelineCode);
-			timelines.put(timelineCode, tb);
+			TimelineBean tb = new TimelineBean(timebands.size() + 1, timelineCode, timelineCode);
+			timebands.put(timelineCode, tb);
 		}
 	}
-
+	
 	private void addEventTypeIfNotExists(final String eventType) {
 		if (!eventTypes.containsKey(eventType)) {
 			// debatable as to whether or not we want to set the id here...
@@ -129,10 +147,11 @@
 		List<TimelineEventBean> events = readDataFromTimelineDirectory(directoryPath);
 
 		// first parse - get all the different timeline and populate timeline
-		// table
-		// also add what's in the importance field in case it's not there
-		// already
-		populateTimelineTable(events);
+		// table  also add what's in the importance field in case it's not there already		
+		//TODO: actually there is a hierarchy between timebands and sub_timebands that is not modelled
+		//although would need to check whether the hierarchy is true
+		populateTimebandTable(events);
+		populateSubTimebandTable(events);
 		populateEventTypeTable(events);
 		populateEventsTable(events);
 	}
@@ -167,6 +186,8 @@
 		// set up the key factory once
 		KeyFactory keyFactory = PassageKeyFactory.instance();
 
+		
+		//TODO: change insert statement to allow timeband_id and subtime_band_id to be populated.
 		try {
 			for (TimelineEventBean event : events) {
 				// System.out.println(event.getName() + " " + event.getID() +
@@ -184,8 +205,9 @@
 				setDate(timelineInsert, timelineParameterIndex++, to); // to_date
 				setString(timelineInsert, timelineParameterIndex++, "" + from.getPrecision().getShortCode()); // from_precision
 				setString(timelineInsert, timelineParameterIndex++, "" + to.getPrecision().getShortCode()); // to_precision
-				timelineInsert.setInt(timelineParameterIndex++, timelines.get(event.getTimeline()).getTimelineId()); // timeline_id
-				timelineInsert.setInt(timelineParameterIndex++, timelines.get(event.getImportance()).getTimelineId()); // importance_id
+				timelineInsert.setInt(timelineParameterIndex++, timebands.get(event.getTimebandId()).getTimelineId()); // timeband_id
+				timelineInsert.setInt(timelineParameterIndex++, subTimebands.get(event.getTimeline()).getTimelineId()); // timeband_id
+				timelineInsert.setInt(timelineParameterIndex++, subTimebands.get(event.getImportance()).getTimelineId()); // importance_id
 				setString(timelineInsert, timelineParameterIndex++, event.getCertainty()); // certainty
 				setString(timelineInsert, timelineParameterIndex++, event.getFlags()); // flags
 				timelineInsert.setInt(timelineParameterIndex++, eventTypes.get(event.getType()).getEventTypeId()); // event_type_id
@@ -255,19 +277,37 @@
 	 * @throws SQLException
 	 *             error running the sql statement
 	 */
-	private void populateTimelineTable(final List<TimelineEventBean> events) throws SQLException {
-		timelines = new HashMap<String, TimelineBean>();
+	private void populateTimebandTable(final List<TimelineEventBean> events) throws SQLException {
+		timebands = new HashMap<String, TimelineBean>();
 
 		for (TimelineEventBean event : events) {
-			addTimelineIfNotExists(event.getTimeline());
-			addTimelineIfNotExists(event.getImportance());
+			addTimebandIfNotExists(event.getTimebandId());
 		}
 
-		for (TimelineBean timeline : timelines.values()) {
+		for (TimelineBean timeline : timebands.values()) {
 			executeSQLText(timeline.getInsertStatement());
 		}
 	}
 
+	/**
+	 * populates the sub timeband table in a similar way to above
+	 * @param events
+	 * @throws SQLException
+	 */
+	private void populateSubTimebandTable(final List<TimelineEventBean> events) throws SQLException {
+		subTimebands = new HashMap<String, TimelineBean>();
+
+		for (TimelineEventBean event : events) {
+			addSubTimebandIfNotExists(event.getTimeline());
+			addSubTimebandIfNotExists(event.getImportance());
+		}
+
+		for (TimelineBean timeline : subTimebands.values()) {
+			executeSQLText(timeline.getSubTimebandInsertStatement());
+			//TODO: in any case this is poor as not using prepared statement
+		}
+	}
+	
 	private void populateEventTypeTable(List<TimelineEventBean> events) throws SQLException {
 		eventTypes = new HashMap<String, EventTypeBean>();
 
@@ -277,7 +317,7 @@
 
 		for (EventTypeBean eventType : eventTypes.values()) {
 			executeSQLText(eventType.getInsertStatement());
+			//TODO: in any case this is poor as not using prepared statement
 		}
 	}
-
 }

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/CachingDispatchAsync.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/CachingDispatchAsync.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/CachingDispatchAsync.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -8,6 +8,7 @@
 import net.customware.gwt.dispatch.shared.Action;
 import net.customware.gwt.dispatch.shared.Result;
 
+//TODO: investigate the user of this client side cache
 /**
  * Dispatcher which support caching of data in memory
  * 
@@ -30,7 +31,7 @@
 	}
 
 	/**
-	 * Execute the give Action. If the Action was executed before it will get fetched from the cache
+	 * Execute the given Action. If the Action was executed before it will get fetched from the cache
 	 * 
 	 * @param <A> Action implementation
 	 * @param <R> Result implementation

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/TimelinePresenter.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/TimelinePresenter.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/TimelinePresenter.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -1,5 +1,7 @@
 package com.tyndalehouse.step.web.client.presenter;
 
+import java.util.List;
+
 import net.customware.gwt.dispatch.client.DispatchAsync;
 import net.customware.gwt.presenter.client.DisplayCallback;
 import net.customware.gwt.presenter.client.EventBus;
@@ -9,30 +11,50 @@
 import net.customware.gwt.presenter.client.widget.WidgetPresenter;
 
 import com.allen_sauer.gwt.log.client.Log;
-import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.event.dom.client.HasClickHandlers;
 import com.google.inject.Inject;
-import com.tyndalehouse.step.web.client.widgets.timeline.TimeLineWidget;
-import com.tyndalehouse.step.web.client.widgets.timeline.TimelineXMLHandler;
+import com.tyndalehouse.step.web.client.toolkit.timeline.TimeBand;
+import com.tyndalehouse.step.web.client.toolkit.timeline.TimeBandNotFoundException;
+import com.tyndalehouse.step.web.client.toolkit.timeline.TimeEvent;
+import com.tyndalehouse.step.web.client.toolkit.timeline.Timeline;
+import com.tyndalehouse.step.web.client.toolkit.timeline.Unit;
+import com.tyndalehouse.step.web.shared.beans.TimeBandVisibleDate;
+import com.tyndalehouse.step.web.shared.beans.TimelineBean;
+import com.tyndalehouse.step.web.shared.beans.TimelineEventBean;
 import com.tyndalehouse.step.web.shared.command.GetEventsForDateRangeCommand;
 import com.tyndalehouse.step.web.shared.command.GetTimelineUISetupCommand;
+import com.tyndalehouse.step.web.shared.event.TimelineScrollEvent;
+import com.tyndalehouse.step.web.shared.eventhandler.TimelineScrollEventHandler;
 import com.tyndalehouse.step.web.shared.result.GetEventsForDateRangeResult;
 import com.tyndalehouse.step.web.shared.result.GetTimelineUISetupResult;
 
-public class TimelinePresenter extends WidgetPresenter<TimelinePresenter.Display> implements TimelineXMLHandler {
+public class TimelinePresenter extends WidgetPresenter<TimelinePresenter.Display> {
 	private final DispatchAsync dispatcher;
 
 	@Inject
-	public TimelinePresenter(Display display, EventBus eventBus, 
-			DispatchAsync dispatcher) {
+	public TimelinePresenter(Display display, EventBus eventBus, DispatchAsync dispatcher) {
 		super(display, eventBus);
 		this.dispatcher = dispatcher;
-		
+
 		bind();
 	}
 
 	public interface Display extends WidgetDisplay {
+		Timeline getTimeline();
 
-		TimeLineWidget getTimelineWidget();
+		/**
+		 * the zoom in Button
+		 * @return
+		 */
+		HasClickHandlers getZoomIn();
+		
+		/**
+		 * The zoom out button
+		 * @return
+		 */
+		HasClickHandlers getZoomOut();
 	}
 
 	@Override
@@ -43,19 +65,6 @@
 
 	@Override
 	protected void onBind() {
-		//initialise widget:
-//        popupBusy.show();
-        
-        // ---------------------------------------------------------------
-        // Got to get ref to widget 
-        // ---------------------------------------------------------------
-		//Needs to be deferred and apparently the timeline widget isn't initialised yet...
-		//TODO: investigate post bind event?
-	 
-		//CommandLoadDataset command = new CommandLoadDataset(TimelinePresenter.this, getDisplay().getTimelineWidget());
-		//DeferredCommand.addCommand(command);
-	
-		
 		dispatcher.execute(new GetTimelineUISetupCommand(), new DisplayCallback<GetTimelineUISetupResult>(display) {
 
 			@Override
@@ -66,197 +75,152 @@
 			@Override
 			protected void handleSuccess(GetTimelineUISetupResult setupData) {
 				Log.debug("Succesfully got timeline setup data");
-				//getDisplay().getTimelineWidget().resetBands(setupData.getTimelines());
+				setupTimeline(setupData);
+			}
+		});
 
-//		    	List<TimelineBean> distinctTimelines = setupData.getTimelines();
-//		    	TimeLineWidget widget = getDisplay().getTimelineWidget();
-//		    	
-//		    	Theme theme = widget.getTheme();
-////		        theme.setEventLabelWidth(400);
-////		    	
-//		    	List<BandInfo> bandInfos = widget.getBandInfos();
-//		    	List<HotZoneBandOptions> bandHotZones = widget.getBandHotZones();
-//		    	List<HighlightDecorator> bandDecorators = widget.getBandDecorators();
-//		    	EventSource eventSource = widget.getEventSource();
-//		        
-//		    	
-//		    	BandOptions bandOptions = null;
-//		    	for(TimelineBean tb : distinctTimelines) {
-//		            bandOptions = BandOptions.create();            
-//		            bandOptions.setWidth("%d%"  + (100 / distinctTimelines.size()));			//this seems to be the height
-//		            //bottomOpts.setTrackHeight(1.3f);
-//		            //bottomOpts.setTrackGap(0.1f);
-//		            
-//		            //this is the timespan that the timeline goes across... 
-//		            long tms = tb.getMaxDate() -  tb.getMinDate();
-//		            long ts = tms / 1000;
-//		            long tmin = ts / 60;
-//		            long thour = tmin / 60; 
-//		            long tday = thour / 24;
-//		            long tyear = tday / 365;
-//		            long tmonth = tyear * 12;
-//		            long tdecade = tyear / 10;
-//		            long tcentury = tdecade / 10;
-//		            long tmilenium = tcentury / 10;
-//		            
-//		            //now work out what the order of magnitude is... are we covering years, centuries, decades...
-//		            //say we're talking about Jesus' life timespan, that's maybe 40 years worth, and we have 60 events on them...
-//		            
-//		            if(tmilenium > 1) {
-//		            	bandOptions.setIntervalUnit(DateTime.MILLENNIUM());
-//		            } else if(tcentury > 1) {
-//		            	bandOptions.setIntervalUnit(DateTime.CENTURY());
-//		            	
-//		            } else if (tdecade > 1) {
-//		            	bandOptions.setIntervalUnit(DateTime.DECADE());
-//		            
-//		            } else if (tmonth > 1) {
-//		            	bandOptions.setIntervalUnit(DateTime.MONTH());
-//		            	
-//		            } else {
-//		            	bandOptions.setIntervalUnit(DateTime.DAY());
-//		            	
-//		            }
-//
-//		            bandOptions.setIntervalPixels(100);
-//		            bandOptions.setShowEventText(true);
-//		            bandOptions.setTheme(theme);
-//		            bandOptions.setEventSource(eventSource);
-//		            bandOptions.setDate("1 AD");
-//		            bandOptions.setZones(bandHotZones);
-//		            bandOptions.setTimeZone(0);
-//		            
-//		            BandInfo info = BandInfo.create(bandOptions);
-//		            info.setDecorators(bandDecorators);
-//		            bandInfos.add(info);
-//		            
-//		    	}
-//
-//		    	BandInfo bottom = BandInfo.createHotZone(bandOptions);
-//		    	bottom.setDecorators(bandDecorators);
-//		    	bandInfos.add(bottom);
-//		    	bottom.setSyncWith(0);
-//		    	bottom.setHighlight(true);   
-//		  
-//			
+		// TODO: all those anonymous classes make the code rather untidy... can
+		// we possible put
+		// all this somewhere else?
+		eventBus.addHandler(TimelineScrollEvent.TYPE, new TimelineScrollEventHandler() {
+			@Override
+			public void onScroll(final TimelineScrollEvent event) {
+				dispatcher.execute(new GetEventsForDateRangeCommand(event.getTimebandVisibleDates()),
+						new DisplayCallback<GetEventsForDateRangeResult>(display) {
+							@Override
+							protected void handleFailure(Throwable e) {
+								Log.error("An error occurred while tyring to get events for the timeline", e);
+							}
+
+							@Override
+							protected void handleSuccess(GetEventsForDateRangeResult resultingEvents) {
+								Log.debug("Request for events came back succesfully!");
+								Log.debug("Request was for " + event.getTimebandVisibleDates().size() + " timebands.");
+
+								List<TimelineEventBean> events = resultingEvents.getEvents();
+								Timeline tl = getDisplay().getTimeline();
+								for (TimelineEventBean ev : events) {
+									int timebandId = ev.getTimelineId();
+
+									try {
+										TimeBand correctBand = tl.getBand(timebandId);
+										correctBand.addEvent(new TimeEvent(ev.getEventId(), ev.getName(), ev.getFromDate(), ev.getToDate(),
+												correctBand));
+									} catch (TimeBandNotFoundException e) {
+										Log.debug("Could not find timeband");
+									}
+								}
+
+								// now that we've added something, we can notify
+								// the timebands that their minimum
+								// received windows are slightly more
+								for (TimeBandVisibleDate tbvd : event.getTimebandVisibleDates()) {
+									try {
+										TimeBand tb = tl.getBand(tbvd.getTimebandId());
+										tb.adjustRequestedView(tbvd.getMinDate(), tbvd.getMaxDate());
+									} catch (TimeBandNotFoundException e) {
+										//if for some reason the timeband has gone, we can but ignore
+										//the error
+										Log.error("Timeband " + tbvd.getTimebandId() + " cannot be found.");
+									}
+								}
+							}
+						});
 			}
 		});
 
+		display.getZoomIn().addClickHandler(new ClickHandler() {
 
-        
-        
+			@Override
+			public void onClick(ClickEvent event) {
+				//call zoom in on the timeline widget
+				display.getTimeline().zoomIn();
+			}
+		});
 		
-//		eventBus.addHandler(NewArticleSelectedEvent.TYPE, new NewArticleSelectedEventHandler() {
-//			@Override
-//			public void onNewArticleSelected(NewArticleSelectedEvent event) {
-//				
-//			}
-//			
-//			
-//		});
-//
-//		eventBus.addHandler(MultipleWordsSelectedEvent.TYPE, new MultipleWordsSelectedEventHandler() {
-//			@Override
-//			public void onMultipleWordsSelected(MultipleWordsSelectedEvent event) {				
-//			}
-//		});
-//
-//		eventBus.addHandler(WordSelectedEvent.TYPE, new WordSelectedEventHandler() {
-//			@Override
-//			public void onWordSelectedEvent(WordSelectedEvent event) {
-//				
-//			}
-//		});		
+		display.getZoomOut().addClickHandler(new ClickHandler() {
 
+			@Override
+			public void onClick(ClickEvent event) {
+				//call zoom in on the timeline widget
+				display.getTimeline().zoomOut();
+			}
+		});
+
 		
+		// eventBus.addHandler(NewArticleSelectedEvent.TYPE, new
+		// NewArticleSelectedEventHandler() {
+		// @Override
+		// public void onNewArticleSelected(NewArticleSelectedEvent event) {
+		//				
+		// }
+		//			
+		//			
+		// });
+		//
+		// eventBus.addHandler(MultipleWordsSelectedEvent.TYPE, new
+		// MultipleWordsSelectedEventHandler() {
+		// @Override
+		// public void onMultipleWordsSelected(MultipleWordsSelectedEvent event)
+		// {
+		// }
+		// });
+		//
+		// eventBus.addHandler(WordSelectedEvent.TYPE, new
+		// WordSelectedEventHandler() {
+		// @Override
+		// public void onWordSelectedEvent(WordSelectedEvent event) {
+		//				
+		// }
+		// });
 	}
 
+	protected void setupTimeline(GetTimelineUISetupResult setupData) {
+		Timeline timeline = display.getTimeline();
+
+		// copy across to UI widget
+		// we could avoid the copying here, since the timline bean
+		// is essentially what is needed, but nice to have it decoupled.
+		for (TimelineBean tb : setupData.getTimelines()) {
+			TimeBand band = new TimeBand(timeline, tb.getTimelineId());
+
+			// TODO: change the scale dynamically
+			band.setPixelsPerUnit(100);
+			band.setHeight(100);
+			band.setUnit(Unit.DECADE);		//TODO: what if i want 8 years, or 25 years, etc.
+
+			// set the date to the middle of the band: TODO: again something
+			// that needs changing.
+			//band.setCurrentDate((tb.getMaxDate() + tb.getMinDate()) / 2);
+			band.setCurrentDate(-61183987174853L); //one of the events in Jesus' life
+			band.setCurrentDateX(400);
+			timeline.addBand(band);
+		}
+
+		timeline.fireTimelineScrollEvent();
+	}
+
 	@Override
 	protected void onPlaceRequest(PlaceRequest request) {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	protected void onUnbind() {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void refreshDisplay() {
 		// TODO Auto-generated method stub
-		
+
 	}
 
 	@Override
 	public void revealDisplay() {
 		// TODO Auto-generated method stub
-		
-	}
 
-	@Override
-	public void onCompletion(JavaScriptObject xml, String url) {
-    	//TODO: this needs to change...
-		String xmlText = "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <data> 	<event start=\"4000 BC\" end=\"3200 BC\" isDuration=\"true\" 		title=\"Winterbourne Stoke Long Barrow\" icon=\"../image/green-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://www.english-heritage.org.uk/stonehengeinteractivemap/sites/winterbourne_stoke/02.html\" title=\"English Heritage\"&gt;         English Heritage         &lt;img id=\"link\" src=\"site/image/yellow-circle.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt; 	</event> 	<event start=\"3000 BC\" end=\"2500 BC\" isDuration=\"true\" 		title=\"Winterbourne Stoke Round Barrows\" icon=\"../image/green-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://www.english-heritage.org.uk/stonehengeinteractivemap/sites/winterbourne_stoke/02.html\" title=\"English Heritage\"&gt;         English Heritage         &lt;img id=\"link\" src=\"site/image/yellow-circle.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt; 	</event> 	<event start=\"3000 BC\" end=\"2500 BC\" isDuration=\"true\" title=\"King Barrows\" 		icon=\"../image/green-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://www.english-heritage.org.uk/stonehengeinteractivemap/sites/king_barrow_ridge/01.html\" title=\"English Heritage\"&gt;         English Heritage         &lt;img id=\"link\" src=\"site/image/yellow-circle.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt; 	</event> 	<event start=\"2500 BC\" end=\"1600 BC\" isDuration=\"true\" 		title=\"Normanton Down Barrows\" icon=\"../image/green-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://www.english-heritage.org.uk/stonehengeinteractivemap/sites/normanton/01.html\" title=\"English Heritage\"&gt;         English Heritage         &lt;img id=\"link\" src=\"site/image/yellow-circle.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt; 	</event> 	 	<event start=\"3100 BC\" title=\"The Cursus\" icon=\"../image/green-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://www.english-heritage.org.uk/stonehengeinteractivemap/sites/cursus/01.html\" title=\"English Heritage\"&gt;         English Heritage         &lt;img id=\"link\" src=\"site/image/yellow-circle.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;                  &lt;a href=\"http://en.wikipedia.org/wiki/Cursus\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         Cursus was a name given by early British archaeologists such as William Stukeley to the large parallel lengths of banks with external ditches which they thought were early Roman athletics tracks, hence the Latin name 'Cursus', meaning 'Circus'. Cursus monuments are now understood to be Neolithic structures and may have been of ceremonial function. 	</event> 	<event start=\"3100 BC\" end=\"2400 BC\" isDuration=\"true\" title=\"Durrington Walls\" 		icon=\"../image/green-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://www.english-heritage.org.uk/stonehengeinteractivemap/sites/durrington_walls/01.html\" title=\"English Heritage\"&gt;         English Heritage         &lt;img id=\"link\" src=\"site/image/yellow-circle.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt; 	</event> 	<event start=\"2600 BC\" end=\"1700 BC\" isDuration=\"true\" title=\"The Avenue\" 		icon=\"../image/green-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://www.english-heritage.org.uk/stonehengeinteractivemap/sites/avenue/01.html\" title=\"English Heritage\"&gt;         English Heritage         &lt;img id=\"link\" src=\"site/image/yellow-circle.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt; 	</event> 	<event start=\"2300 BC\" end=\"2000 BC\" isDuration=\"true\" title=\"Woodhenge\" 		icon=\"../image/green-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://en.wikipedia.org/wiki/Woodhenge\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         Woodhenge is a Neolithic Class I henge and timber circle monument located to the North of Amesbury in Wiltshire, England, and it is closer to Amesbury than is Stonehenge. 	</event> 	<event start=\"1100 BC\" end=\"500 BC\" isDuration=\"true\" title=\"Vespasian's Camp\" 		icon=\"../image/green-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://www.english-heritage.org.uk/stonehengeinteractivemap/sites/vespasians_camp/01.html\" title=\"English Heritage\"&gt;         English Heritage         &lt;img id=\"link\" src=\"site/image/yellow-circle.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt; 	</event> 	 	<event start=\"2900 BC\" end=\"2700 BC\" title=\"Phase 1 - Earthwork Enclosure\" 		icon=\"../image/blue-circle.png\" image=\"../image/Timeline_Logo_Thumb.png\"> 	</event> 	<event start=\"2900 BC\" end=\"2400 BC\" title=\"Phase 2 - Wooden Structures\" 		icon=\"../image/blue-circle.png\" image=\"../image/Timeline_Logo_Thumb.png\"> 	</event> 	<event start=\"2600 BC\" end=\"1600 BC\" title=\"Phase 3 - Stone Circle \" 		icon=\"../image/blue-circle.png\" image=\"../image/Timeline_Logo_Thumb.png\"> 	</event> 	 	<event start=\"3100 BC\" title=\"Stonehenge 1\" icon=\"../image/red-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://en.wikipedia.org/wiki/Stonehenge#Stonehenge_1\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         The first monument consisted of a circular bank and ditch enclosure. 	</event> 	<event start=\"3000 BC\" title=\"Stonehenge 2\" icon=\"../image/red-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://en.wikipedia.org/wiki/Stonehenge#Stonehenge_2\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         Evidence of the second phase is no longer visible. It appears from the number of postholes dating to this period that some form of timber structure was built within the enclosure during the early 3rd millennium BC. 	</event> 	<event start=\"2600 BC\" title=\"Stonehenge 3 I\" icon=\"../image/red-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://en.wikipedia.org/wiki/Stonehenge#Stonehenge_3_I\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         Archaeological excavation has indicated that around 2600 BC, timber was abandoned in favour of stone and two concentric crescents of holes (called the Q and R Holes) were dug in the centre of the site. 	</event> 	<event start=\"2440 BC\" end=\"2100 BC\" title=\"Stonehenge 3 II\" 		icon=\"../image/red-circle.png\" image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://en.wikipedia.org/wiki/Stonehenge#Stonehenge_3_II\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         The next major phase of activity at the tail end of the 3rd millennium BC saw 30 enormous sarsen stones brought from a quarry around 24 miles (40 km) north to the site on the Marlborough Downs. 	</event> 	<event start=\"2100 BC\" title=\"Stonehenge 3 III\" icon=\"../image/red-circle.png\" 		image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://en.wikipedia.org/wiki/Stonehenge#Stonehenge_3_III\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         Later in the Bronze Age, the bluestones appear to have been re-erected for the first time, although the precise details of this period are still unclear. 	</event> 	<event start=\"2280 BC\" end=\"1930 BC\" title=\"Stonehenge 3 IV\" 		icon=\"../image/red-circle.png\" image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://en.wikipedia.org/wiki/Stonehenge#Stonehenge_3_IV\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         This phase saw further rearrangement of the bluestones as they were placed in a circle between the two settings of sarsens and in an oval in the very centre. Some archaeologists argue that some of the bluestones in this period were part of a second group brought from Wales. 	</event> 	<event start=\"2270 BC\" end=\"1930 BC\" title=\"Stonehenge 3 V\" 		icon=\"../image/red-circle.png\" image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://en.wikipedia.org/wiki/Stonehenge#Stonehenge_3_V\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         Soon afterwards, the north eastern section of the Phase 3 IV Bluestone circle was removed, creating a horseshoe-shaped setting termed the Bluestone Horseshoe. 	</event> 	<event start=\"1930 BC\" end=\"1600 BC\" title=\"Stonehenge 3 VI\" 		icon=\"../image/red-circle.png\" image=\"../image/Timeline_Logo_Thumb.png\">         &lt;a href=\"http://en.wikipedia.org/wiki/Stonehenge#Stonehenge_3_VI\" title=\"Wikipedia article\"&gt;         &lt;img id=\"link\" src=\"site/image/Wiki_letter_w.png\" border=\"0\"&gt;&lt;/img&gt;&lt;/a&gt;         Two further rings of pits were dug outside the outermost sarsen circle. 	</event> 	 </data>";
-    	
-    	// Load eventsource with returned xml
-        getDisplay().getTimelineWidget().getEventSource().loadXMLText(xmlText);
-        
-        // We need to send a resize message to 'fix' the display window size.
-        //TODO: fix the display window size?
-        
-        //TimeLineTest.getMainPanel().onWindowResized(Window.getClientWidth(), Window.getClientHeight());
-		
 	}
-
-	@Override
-	public void onScroll(String minDate, String maxDate) {
-		//Log.debug("WOW! I was called! Amazing!" + minDate + " " + maxDate);
-		
-		
-		//TODO: ensure they are longs
-		long min = Long.parseLong(minDate);
-		long max = Long.parseLong(maxDate);
-		
-		//TODO: ensure that it doesn't get called for every millisecond change!
-		//add some state to the timeline...
-		
-		//build command from UI, but for now, let's do it manuall
-		GetEventsForDateRangeCommand cmd = new GetEventsForDateRangeCommand(min, max);
-		cmd.setShowDuration(false);
-		
-		
-		dispatcher.execute(new GetEventsForDateRangeCommand(min, max), new DisplayCallback<GetEventsForDateRangeResult>(display) {
-
-			@Override
-			protected void handleFailure(Throwable e) {
-				Log.error("An error occurred while tyring to get events for the timeline", e);
-			}
-
-			@Override
-			protected void handleSuccess(GetEventsForDateRangeResult resultingEvents) {
-
-//				Log.debug("XML is: " + resultingEvents.getXml());
-				getDisplay().getTimelineWidget().addEvents(resultingEvents.getEvents());
-//				getDisplay().getTimelineWidget().getEventSource().loadXMLText(resultingEvents.getXml());
-		        
-			}
-		});
-		
-		
-		//TODO: we probably want to fire an event here just in case...
-		
-
-		//pass these down to the server layer...
-		
-		
-		//so the process will be
-		//1. determine whether the timeline has changed significantly
-		
-		//2. get the new data from the database if required
-		
-		//3. ensure that the data gets pushed back to the page, perhaps without duplicates!
-		
-	}
 }

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/CannotDeleteEventException.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/CannotDeleteEventException.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/CannotDeleteEventException.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,15 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+public class CannotDeleteEventException extends Exception {
+
+	public CannotDeleteEventException(final String message) {
+		super(message);
+	}
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -9221252482310063155L;
+	
+	
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/IncapableOfCalculatingRequestWindowException.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/IncapableOfCalculatingRequestWindowException.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/IncapableOfCalculatingRequestWindowException.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,13 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+public class IncapableOfCalculatingRequestWindowException extends Exception {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1866493907904681758L;
+
+	public IncapableOfCalculatingRequestWindowException(final String message) {
+		super(message);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/RequestWindow.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/RequestWindow.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/RequestWindow.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,5 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+public class RequestWindow {
+
+}

Deleted: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/ScaleBand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/ScaleBand.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/ScaleBand.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -1,68 +0,0 @@
-package com.tyndalehouse.step.web.client.toolkit.timeline;
-
-import com.allen_sauer.gwt.log.client.Log;
-import com.extjs.gxt.ui.client.core.El;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Element;
-
-/**
- * The TimeBand object represents a section of the timeline that contains the events.
- * @author CJBurrell
- *
- */
-public class ScaleBand extends TimeBand {
-	public ScaleBand(final Timeline parent, final String name) {
-		super(parent, name);
-		//override 
-	}
-	
-	@Override
-	protected void initDivProperties() {
-		getBandDiv().setClassName("step-scaleband");
-	}
-
-	@Override
-	protected void addBandToUI(int top) {
-		super.addBandToUI(top);
-		
-		Element div = getElement();
-		El gxtDiv = new El(div);
-		
-		gxtDiv.setStyleName("step-scale-band", true);
-		
-		//TODO: change this at some point
-		int width = 64000;
-
-		Unit unit = getUnit();
-		int pixelsPerUnit = getPixelsPerUnit();
-		
-		//how many do i need to generate?
-		int numberOfMarkers = width / pixelsPerUnit;
-		for(int ii = 0; ii < numberOfMarkers; ii++) {
-			Element un = DOM.createDiv();
-			El gxtUn = new El(un);
-			gxtUn.setWidth(pixelsPerUnit);
-			
-			un.setInnerText(""+ii);
-			div.appendChild(un);
-		}
-		
-		
-		
-		//calculate the date
-		
-		Log.debug("client width: " + div.getClientWidth());
-//		gxtDiv.appendChild(un);
-		
-		
-		
-		
-		
-		//also add all the markings for the dates on the band
-	}
-
-
-}
-
-
-

Deleted: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/ScrollListener.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/ScrollListener.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/ScrollListener.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -1,5 +0,0 @@
-package com.tyndalehouse.step.web.client.toolkit.timeline;
-
-public interface ScrollListener {
-
-}

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeBand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeBand.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeBand.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -2,12 +2,13 @@
 
 import java.util.TreeMap;
 
-import com.allen_sauer.gwt.log.client.Log;
 import com.extjs.gxt.ui.client.core.El;
 import com.google.gwt.event.dom.client.MouseDownEvent;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Window;
 import com.google.gwt.user.client.ui.Widget;
+import com.tyndalehouse.step.web.shared.beans.TimeBandVisibleDate;
 
 /**
  * The TimeBand object represents a section of the timeline that contains the
@@ -16,74 +17,113 @@
  * @author CJBurrell
  * 
  */
+//TODO: add another container around the scale band to ensure that the writing doesn't overlap
+//or change the location of the scale band to be at the bottom rather than at the top of each band
 public class TimeBand extends Widget {
 
 	/* business rules */
-	private String id;
-	private String name;
+	private int id;
 	private long minDate;
 	private long maxDate;
 
 	/**
 	 * this contains all the events on the time band
 	 */
-	private TreeMap<String, TimeEvent> events;
+	private TreeMap<Integer, TimeEvent> events;
 
 	/* graphical properties */
-	private boolean visible = true;
 	private Unit unit;
 
 	private Element bandDiv;
-	
-	/** height of the time band, defaults at 50px*/
+
+	/** height of the time band, defaults at 50px */
 	private int height = 100;
-	
+
 	private int pixelsPerUnit;
 
 	/**
 	 * this is the parent widget.
 	 */
 	private final Timeline parent;
+
+	// TODO: adjust this
 	private long currentDate;
+	private long currentDateX = 0;
 
-	// TODO: adjust this
-	private long currentDateX = 200;
 	private boolean showScale = true;
 	private int mouseDownScrollLeft;
 	private Element timebandContainer;
 
 	/**
-	 * @return the showScale
+	 * This indicates whether the band has been painted and is showing
 	 */
-	public boolean isShowScale() {
-		return showScale;
-	}
-
+	private boolean isRendered = false;
+	
 	/**
-	 * @param showScale the showScale to set
+	 * This is the timescale visible on the timeband drawing lines across the timebands
+	 * for each unit
 	 */
-	public void setShowScale(boolean showScale) {
-		this.showScale = showScale;
-	}
-
-	public TimeBand(final Timeline parent, final String id) {
+	private TimeScale timescale;
+	
+	/**
+	 * this is the autohide option, which should hide the timeband if no events are displayed
+	 */
+	private boolean autoHide = true;
+	
+	/**
+	 * when this is set to true, then we can use the request window object
+	 * to determine whether or not we are showing all the events we are able to
+	 * If events can be deleted or moved to other timebands, it becomes difficult to work out
+	 * what the request window should be.
+	 */
+	private boolean deletionsDisabled= true;
+	private TimebandRequestWindow requestWindow = null;
+	
+	//TODO:Derive this from a properties file? somehow? or database?
+	/**
+	 * this describes how much of a unit needs to be visible before calling back to the server
+	 */
+	private double outstandingUnitFactor = 0.5;
+	
+	/**
+	 * This determines how much of a zoom is applied. For example
+	 * a factor of 0.25 changes the scale of 50 pixels per decade to
+	 * (1 + 0.25) * 50 = 75 pixels
+	 */
+	private double zoomFactor = 0.25;
+	
+	public TimeBand(final Timeline parent, final int id) {
 		this.parent = parent;
 		this.id = id;
-		
-		
-		events = new TreeMap<String, TimeEvent>();
+
+		events = new TreeMap<Integer, TimeEvent>();
 		bandDiv = DOM.createDiv();
 		timebandContainer = DOM.createDiv();
-		
+
 		initDivProperties();
 		setElement(timebandContainer);
 	}
-		
+
 	protected void initDivProperties() {
 		bandDiv.setClassName("step-timeband");
 	}
 
 	/**
+	 * @return the showScale
+	 */
+	public boolean isShowScale() {
+		return showScale;
+	}
+
+	/**
+	 * @param showScale
+	 *            the showScale to set
+	 */
+	public void setShowScale(boolean showScale) {
+		this.showScale = showScale;
+	}
+
+	/**
 	 * @return the bandDiv
 	 */
 	public Element getBandDiv() {
@@ -114,24 +154,9 @@
 	}
 
 	/**
-	 * @return the visible
-	 */
-	public boolean isVisible() {
-		return visible;
-	}
-
-	/**
-	 * @param visible
-	 *            the visible to set
-	 */
-	public void setVisible(boolean visible) {
-		this.visible = visible;
-	}
-
-	/**
 	 * @return the id
 	 */
-	public String getId() {
+	public int getId() {
 		return id;
 	}
 
@@ -139,26 +164,11 @@
 	 * @param id
 	 *            the id to set
 	 */
-	public void setId(String id) {
+	public void setId(int id) {
 		this.id = id;
 	}
 
 	/**
-	 * @return the name
-	 */
-	public String getName() {
-		return id;
-	}
-
-	/**
-	 * @param name
-	 *            the name to set
-	 */
-	public void setName(String name) {
-		this.id = name;
-	}
-
-	/**
 	 * @return the minDate
 	 */
 	public long getMinDate() {
@@ -206,25 +216,45 @@
 	/**
 	 * @return the events
 	 */
-	public TreeMap<String, TimeEvent> getEvents() {
+	public TreeMap<Integer, TimeEvent> getEvents() {
 		return events;
 	}
 
 	public void addEvent(TimeEvent event) {
-		events.put(event.getId(), event);
+		// need to check the event isn't already in our list:
+		if (!events.containsKey(event.getId())) {
+			events.put(event.getId(), event);
 
-		// TODO: refresh the timeline dom.
+			if (isVisible()) {
+				//Log.debug("Request to paint event triggered");
+				event.paint();
+			} else if (autoHide) {
+				// well the band is not visible, so if the event is in the
+				// visible section, then paint it
+				if (isEventInVisibleSection(event)) {
+					//Log.debug("Displaying container and requesting paint");
+					El el = new El(timebandContainer);
+					el.setDisplayed(true);
+					event.paint();
+				}
+			}
+			// otherwise, autoHide is set to false, so leave hidden
+		}
 	}
 
 	/**
 	 * Removes an event from the band
 	 * 
-	 * @param id
-	 *            the id of the event to be removed.
+	 * @param id the id of the event to be removed.
+	 * @throws CannotDeleteEventException An event cannot be removed from a timeband.
 	 */
-	public void removeEvent(final String id) {
+	public void removeEvent(final int id) throws CannotDeleteEventException {
+		if(deletionsDisabled) {
+			throw new CannotDeleteEventException("The event you are trying to delete (" + id + ") is on band set on" +
+					"deletionsDisabled = true");
+		}
+		
 		events.remove(id);
-
 		// TODO: refresh the timeline dom
 	}
 
@@ -232,108 +262,120 @@
 		return events.get(eventId);
 	}
 
-	public Long getMinVisibleDate() {
-		// TODO:
-		return null;
+	public long getMinVisibleDate() {
+		return TimeConversionUtil.pixelToTime(
+				timebandContainer.getScrollLeft(), this);
 	}
 
-	public Long getMaxVisibleDate() {
-		// TODO:
-		return null;
+	public long getMaxVisibleDate() {
+		int realClientWidth = timebandContainer.getClientWidth();
+		//if this is not rendered properly yet, then we have no width:
+		if(realClientWidth == 0) {
+			//use the timeline width, perhaps we can take the parent width instead...
+			//this is important as it it could that the timline doesn't take the full width
+			realClientWidth = Window.getClientWidth();
+		}
+		
+		return TimeConversionUtil.pixelToTime(
+				timebandContainer.getScrollLeft() + realClientWidth, this);
 	}
 
-	public void openBubbleForPoint() {
-		// TODO:
-	}
-
-	public void closeAllBubbles() {
-		// TODO:
-
-	}
-
-	public void layout() {
-		// TODO:
-
-	}
-
 	protected void paint() {
 		paint(0);
 	}
-	
+
 	protected void paint(int top) {
-		if (isVisible()) {
+		//Log.debug("Request to paint band id:" + getId() + " Current date: " + getCurrentDate());
+		if (!isRendered) {
 			addBandToUI(top);
-		} else {
-			removeBandFromUI();
+			isRendered = true;
 		}
 
-		//show scale band?
-		if(showScale) {
-			Element scaleBand = DOM.createDiv();
-			El gxtScaleBand = new El(scaleBand);
-			bandDiv.appendChild(scaleBand);
-			
-			gxtScaleBand.setStyleName("step-scale-band", true);
-			
-			//TODO: change this at some point
-			int width = 64000;
-
-			Unit unit = getUnit();
-			int pixelsPerUnit = getPixelsPerUnit();
-			
-			//how many do i need to generate?
-			int relativeLeft = 0;
-			int numberOfMarkers = width / pixelsPerUnit;
-			for(int ii = 0; ii < numberOfMarkers; ii++) {
-				Element un = DOM.createDiv();
-				El gxtUn = new El(un);
-				gxtUn.setWidth(pixelsPerUnit);
-				un.setInnerText(""+ii);
-				gxtScaleBand.appendChild(un);
-				
-				//set left position:
-				gxtUn.setLeft(relativeLeft);
-				gxtUn.setHeight("100%");
-				
-				relativeLeft += pixelsPerUnit;
-			}
-			
-			//new El(bandDiv).setWidth(64000);
+		// show scale band?
+		//TODO: only paint if we're rendering this band
+		if (isRendered && showScale) {
+			if(timescale == null) {
+				timescale = new TimeScale(this);
+			}	
+			timescale.paint();
 		}
 		
-		// get the events to paint themselves
+		// get the events to paint themselves (they will decide whether or not to
+		//paint if they are already showing...
 		for (TimeEvent te : events.values()) {
 			te.paint();
 		}
 	}
 
-	protected void removeBandFromUI() {
-//		parent.getElement().removeChild(bandDiv);
-	}
+	protected void addBandToUI(int top) {
+		El el = new El(timebandContainer);
+		El gxtBandDiv = new El(bandDiv);
 
-	@Override
-	protected void onAttach() {
-		super.onAttach();
-		Log.debug("timeband is attached now" + isAttached());
-	};
-	
-	protected void addBandToUI(int top) {
+		//set display options, ie. auto hide
+		if(autoHide && !hasVisibleEvents()) {
+			el.setDisplayed(false);
+		}
+		
 		parent.getTimelineContainer().appendChild(timebandContainer);
 		timebandContainer.appendChild(bandDiv);
-		
-		El el = new El(timebandContainer);
+
 		el.setStyleName("step-timeband-container");
 		el.setHeight(getHeight());
-		//el.setTop(top);
-		
-		El gxtBandDiv = new El(bandDiv);
+		// el.setTop(top);
+
 		gxtBandDiv.setHeight("100%");
 		gxtBandDiv.setTop(0);
 	}
 
-	public void softPaint() {
-		// TODO: huh?
+	/**
+	 * Tells the caller whether the event is in the visible section of the div on the browser.
+	 * @param event the event to be tested
+	 * @return true if the event is in the visible section
+	 */
+	private boolean isEventInVisibleSection(TimeEvent event) {
+		Long eventMinDate = event.getMinDate();
+		Long eventMaxDate = event.getMaxDate();			//eventMaxDate can be null
+		long minVisibleDate = getMinVisibleDate();
+		long maxVisibleDate = getMaxVisibleDate();
+
+		//output compare option:
+//		DateTimeFormat dtf = DateTimeFormat.getFormat("yyyy G");
+		
+//		Log.debug("Comparing ev(" + 
+//				dtf.format(new Date(eventMinDate)) + "," + 
+//				dtf.format(new Date(eventMaxDate)) + ") " +
+//				"to band(" + 
+//				dtf.format(new Date(minVisibleDate)) + "," + 
+//						dtf.format(new Date(maxVisibleDate)) + ")");
+		
+		if((eventMinDate >= minVisibleDate && eventMinDate <= maxVisibleDate) ||
+			(eventMaxDate != null && eventMaxDate >= minVisibleDate && eventMaxDate <= maxVisibleDate) ||
+			(eventMaxDate != null && eventMinDate <= minVisibleDate && eventMaxDate >= maxVisibleDate)) {
+			return true;
+		}
+
+		return false;
 	}
+	
+	/**
+	 * Checks whether any of the already attached events are in the visible section
+	 * @return
+	 */
+	private boolean hasVisibleEvents() {
+		//first check count of events, this is because perhaps we are initialising 
+		//and we don't have anything else to go on...
+		if(events.size() == 0) {
+			return false;
+		}
+		
+		//check each event to see if they are in the visible section
+		for(TimeEvent event : events.values()) {
+			if(isEventInVisibleSection(event)) {
+				return true;
+			}
+		}
+		return false;
+	}
 
 	public void setCurrentDate(long currentDate) {
 		this.currentDate = currentDate;
@@ -369,7 +411,8 @@
 	}
 
 	/**
-	 * @param height the height to set
+	 * @param height
+	 *            the height to set
 	 */
 	public void setHeight(int height) {
 		this.height = height;
@@ -377,26 +420,180 @@
 
 	public void captureScrollLeft(MouseDownEvent e) {
 		this.mouseDownScrollLeft = timebandContainer.getScrollLeft();
-		
-		Log.debug("mousedown left: " + mouseDownScrollLeft);
-		Log.debug("relative x: " + e.getRelativeX(timebandContainer));
 	}
 
 	public void setScrollLeft(int previousClientX, int newClientX, Unit defaultUnit, int defaultPixelsPerUnit) {
-		//we scroll, but we calculate the unit/scale factor first
-		//say default is 1 Year
-		//this one is 10 years
-		//unit Factor = 0.1 so we scroll 10 times less pixels
+		// we scroll, but we calculate the unit/scale factor first
+		// say default is 1 Year
+		// this one is 10 years
+		// unit Factor = 0.1 so we scroll 10 times less pixels
 		double unitFactor = (double) defaultUnit.getMilliseconds() / (double) unit.getMilliseconds();
-	
-		//now say instead unit factor is 1, ie. the same unit, but different number of pixels
-		//default is 50 pixels per year, this one is 25 pixels a year
-		//so we want to scroll half
+
+		// now say instead unit factor is 1, ie. the same unit, but different
+		// number of pixels
+		// default is 50 pixels per year, this one is 25 pixels a year
+		// so we want to scroll half
 		double pixelFactor = (double) pixelsPerUnit / (double) defaultPixelsPerUnit;
+		this.timebandContainer.setScrollLeft((int) (mouseDownScrollLeft + ((previousClientX - newClientX) * (unitFactor * pixelFactor))));
+	}
+
+	/**
+	 * @return the deletionsDisabled
+	 */
+	public boolean isDeletionsDisabled() {
+		return deletionsDisabled;
+	}
+
+	/**
+	 * @param deletionsDisabled the deletionsDisabled to set
+	 */
+	public void setDeletionsDisabled(boolean deletionsDisabled) {
+		this.deletionsDisabled = deletionsDisabled;
+	}
+
+	/**
+	 * This method is used to tell the Timeband that it now has all events within the section:
+	 * (x1,x2).  We can then use this to ensure subsequent requests don't request the same thing
+	 * from the server, hence reducing load between the server and the client
+	 * and also reducing the load on the server 
+	 * @param minDateRequested the minimum date that was requested and retrieved from the back-end
+	 * @param maxDate2 the maximum date that was requested and retrieved from the back-end
+	 */
+	public void adjustRequestedView(long minDateRequested, long maxDateRequested) {
+		if(requestWindow == null) {
+			requestWindow = new TimebandRequestWindow(minDateRequested, maxDateRequested);
+		} else {
+			requestWindow.adjustRange(minDateRequested, maxDateRequested);
+		}
+	}
+
+	public TimeBandVisibleDate getOustandingTimebandPeriod() throws IncapableOfCalculatingRequestWindowException {
+		long minVisibleDate = getMinVisibleDate();
+		long maxVisibleDate = getMaxVisibleDate();
+		long minimumDifference = (long) (unit.getMilliseconds() * outstandingUnitFactor);
 		
+		//the new requested bit depends on our request window
+		if(requestWindow == null) {
+			return new TimeBandVisibleDate(id, minVisibleDate, maxVisibleDate);
+		} else {
+			//return only the portion that has changed (probably only one pixel worth)! TODO later: ensure
+			//we send requests when they are actually worth sending
+			// -------|--------$------|-----$--------------------
+		    //       mvd      mrd   Mvd      Mrd	
+			long minReceivedDate = requestWindow.getMinDate();
+			long maxReceivedDate = requestWindow.getMaxDate();
+			boolean shiftedLeft = minVisibleDate < minReceivedDate;
+			boolean shiftedRight = maxVisibleDate > maxReceivedDate;
+			
+			if(!shiftedLeft && !shiftedRight) {
+				return TimeBandVisibleDate.getNoRequest();
+			} else if(shiftedLeft && shiftedRight) {
+				//in this case, it was probably a zoom, and so we need to request both parts
+				return new TimeBandVisibleDate(id, minVisibleDate, maxVisibleDate);
+			} else if(shiftedLeft) {
+				//window could potentially have jumped, so there may be a gap between maxVisibleDate and min, so take
+				//check for gap first, and then decide
+				//TODO: check here
+				if(maxVisibleDate < minReceivedDate) {
+					//we have issues here, as we're either going to have to remember about all the already painted stuff
+					//or we're going to have to clear down the band first.
+					//TODO:
+					throw new IncapableOfCalculatingRequestWindowException("You cannot yet scroll so fast as to have the max window " +
+							"be before the min requested");
+				} else {
+					//the max is greater than the minimum so we return
+					if(minReceivedDate - minVisibleDate > minimumDifference) {
+						return new TimeBandVisibleDate(id, minVisibleDate, minReceivedDate);
+					} else {
+						return TimeBandVisibleDate.getNoRequest();
+					}
+				}
+			} else if(shiftedRight) {
+				//same problem as above if
+				if(minVisibleDate > maxReceivedDate) {
+					throw new IncapableOfCalculatingRequestWindowException("You cannot yet scroll so fast as to have the min window " +
+							"end up further than the max requested");
+				} else {
+					//in particular check that the gap between maxReceivedDate and maxVisibleDate is enough
+					if(maxVisibleDate - maxReceivedDate > minimumDifference) {
+						return new TimeBandVisibleDate(id, maxReceivedDate, maxVisibleDate);
+					} else {
+						return TimeBandVisibleDate.getNoRequest();
+					}
+				}
+			} else {
+				//TODO: add the proper debug information to the exception
+				throw new IncapableOfCalculatingRequestWindowException("Unable to calculate request window. It was shifted neither left, nor right");
+			}			
+		}		
+	}
+
+	/**
+	 * @param outstandingUnitFactor the outstandingUnitFactor to set
+	 */
+	public void setOutstandingUnitFactor(double outstandingUnitFactor) {
+		this.outstandingUnitFactor = outstandingUnitFactor;
+	}
+
+	/**
+	 * @return the outstandingUnitFactor
+	 */
+	public double getOutstandingUnitFactor() {
+		return outstandingUnitFactor;
+	}
+
+	public boolean isRendered() {
+		return isRendered;
+	}
+
+	/**
+	 * The way zooming works is that we recalculate the positions of all events on the timeline
+	 */
+	public void zoomOut() {
+		//first change the zoom factor, then repaint events, and the timescale
+		//lets just assume a default zoom factor for now
+		//TODO: zoom in factor to be parameterised
+		zoom(1 - zoomFactor);
 		
+	}
+
+	/**
+	 * 
+	 */
+	public void zoomIn() {
+		zoom(1 + zoomFactor);
+	}
+
+	
+	private void zoom(double zoomRatio) {
+		//TODO: somehow start with those events in the window (although for zoomout, won't make a different
+		//first change the scale
 		
-		this.timebandContainer.setScrollLeft((int) 
-				(mouseDownScrollLeft + ((previousClientX - newClientX) * (unitFactor*pixelFactor))));
+		//TODO: something clever with the unit? for eg. take the ratio with current unit, and see if ratio would
+		//be similar with another unit?
+		//for now however, let's do it simply
+		pixelsPerUnit *= zoomRatio;
+	
+		//TODO: the timescale should technically be in charge of the unit
+		//logically speaking, let's start with the timescale
+		timescale.repaint(zoomRatio);
+		
+		for(TimeEvent te : events.values()) {
+			te.repaint(zoomRatio);
+		}		
 	}
+
+	/**
+	 * @return the zoomFactor
+	 */
+	public double getZoomFactor() {
+		return zoomFactor;
+	}
+
+	/**
+	 * @param zoomFactor the zoomFactor to set
+	 */
+	public void setZoomFactor(double zoomFactor) {
+		this.zoomFactor = zoomFactor;
+	}
 }

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeConversionUtil.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeConversionUtil.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeConversionUtil.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,71 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+import java.util.Date;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+
+public class TimeConversionUtil {
+	//TODO: make these parameterizable?
+	private final static DateTimeFormat year = DateTimeFormat.getFormat("yyyy G");
+	private final static DateTimeFormat month = DateTimeFormat.getFormat("MMM yyyy G");
+	private final static DateTimeFormat day = DateTimeFormat.getFormat("dd/MM/yyyy G");
+	
+	/**
+	 * This takes a pixel position and returns the equivalent time
+	 * @param pixelPosition the pixel position that we are trying to convert
+	 * @param currentDateX the pixel position of the origin
+	 * @param currentDate the time that the origin is set to
+	 * @param unit	the size of a unit
+	 * @param pixelsPerUnit the number of pixels per unit
+	 * @return the time of pixelPosition
+	 */
+	public static long pixelToTime(long pixelPosition, TimeBand timeband) {
+		long currentDateX = timeband.getCurrentDateX();
+		long currentDate = timeband.getCurrentDate();
+		Unit unit = timeband.getUnit();
+		long pixelsPerUnit = timeband.getPixelsPerUnit();
+		
+		
+		long differenceWithOrigin = pixelPosition - currentDateX;
+		long date = currentDate + (differenceWithOrigin * unit.getMilliseconds() / pixelsPerUnit);
+		return date;
+	}
+
+	/**
+	 * A date is always calculated within a time band.
+	 * @param eventDate the date to be converted
+	 * @param timeband
+	 * @return
+	 */
+	public static long timeToPixel(final long eventDate, TimeBand currentTimeband) {
+		// here's what we start from
+		long millisecondPerUnit = currentTimeband.getUnit().getMilliseconds();
+		long pixelsPerUnit = currentTimeband.getPixelsPerUnit();
+		long currentOriginDate = currentTimeband.getCurrentDate();
+		long currentOriginXPixel = currentTimeband.getCurrentDateX();
+
+		// what's one pixel in milliseconds?
+		double onePixelInMs = (double) millisecondPerUnit / pixelsPerUnit;
+
+		// calculate difference with current position on timeband
+		long differenceWithEvent = eventDate - currentOriginDate;
+		long pixelValueOnBand = currentOriginXPixel + (long) (differenceWithEvent / onePixelInMs);
+		return pixelValueOnBand;
+	}
+
+	public static String formatPixelToTime(final long pixelPosition, TimeBand timeband) {
+		return formatTime(pixelToTime(pixelPosition, timeband));
+	}
+	
+	/**
+	 * formats the given time for the moment as yyyy G
+	 * @param eventDate date to be formatted 
+	 * @return the string representation of the date
+	 */
+	public static String formatTime(final long eventDate) {
+		//TODO: change for multiple formats when need be
+		//use the year one for now
+		Date date = new Date(eventDate);
+		return year.format(date);
+	}
+}

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeEvent.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeEvent.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -5,79 +5,84 @@
 import com.google.gwt.user.client.Element;
 
 public class TimeEvent {
-	
-	
-	/** the date of the event, and if a duration, the start date
+
+	/**
+	 * the date of the event, and if a duration, the start date
 	 * 
 	 */
 	private Long minDate;
-	
+
 	/**
 	 * the end date of a duration event
 	 */
-	private Long maxDate; 
-	
+	private Long maxDate;
+
 	/**
 	 * description of the event
 	 */
 	private String description;
-	
+
 	/**
 	 * id of the event
 	 */
-	private String id;
-	
+	private int id;
+
 	/**
 	 * Show event text
 	 */
 	private boolean showText;
 
-	/** 
-	 * default to a standard event or duration
-	 * we will drive this from the database
+	/**
+	 * default to a standard event or duration we will drive this from the
+	 * database
 	 */
 	private String eventType;
-	
 
 	private Element eventDiv;
 	private Element icon;
 	private Element label;
-	
 
 	/**
 	 * events can move from one timeband to another
 	 */
 	private TimeBand currentTimeBand;
-	
-	
-	
-	public TimeEvent(final String id, final String description, final Long minDate, final Long maxDate, final TimeBand tb) {
+
+	private boolean isRendered = false;
+
+	public TimeEvent(final int id, final String description, final Long minDate, final Long maxDate, final TimeBand tb) {
 		this.id = id;
 		this.description = description;
 		this.minDate = minDate;
 		this.maxDate = maxDate;
 
-		if(maxDate == null) {
-			//then it's a point in time
+		if (maxDate == null) {
+			// then it's a point in time
 			eventType = TimelineConstants.POINT_IN_TIME_EVENT;
 		} else {
 			eventType = TimelineConstants.DURATION;
 		}
-		
+
 		this.currentTimeBand = tb;
 		eventDiv = DOM.createDiv();
 		icon = DOM.createDiv();
 		label = DOM.createDiv();
 	}
-	
-	
-	public void moveTimeBand(TimeBand newTimeBand) {
+
+	/**
+	 * This method removes an event from the current timeband
+	 * and moves in onto a different timeband. This will be useful
+	 * when time bands become invisible, or we are not interested
+	 * in most of the timeband, and we want to use the "importance"
+	 * field
+	 * @param newTimeBand the timeband to be moved to
+	 * @throws CannotDeleteEventException An event can't be moved from one timeband to another if deletions are disallowed
+	 */
+	public synchronized void moveTimeBand(TimeBand newTimeBand) throws CannotDeleteEventException {
 		currentTimeBand.removeEvent(this.getId());
 		currentTimeBand = newTimeBand;
 		currentTimeBand.addEvent(this);
 	}
-	
-	
+
 	/**
 	 * @return the minDate
 	 */
@@ -85,17 +90,14 @@
 		return minDate;
 	}
 
-
-
 	/**
-	 * @param minDate the minDate to set
+	 * @param minDate
+	 *            the minDate to set
 	 */
 	public void setMinDate(long minDate) {
 		this.minDate = minDate;
 	}
 
-
-
 	/**
 	 * @return the maxDate
 	 */
@@ -103,17 +105,14 @@
 		return maxDate;
 	}
 
-
-
 	/**
-	 * @param maxDate the maxDate to set
+	 * @param maxDate
+	 *            the maxDate to set
 	 */
 	public void setMaxDate(long maxDate) {
 		this.maxDate = maxDate;
 	}
 
-
-
 	/**
 	 * @return the description
 	 */
@@ -121,30 +120,26 @@
 		return description;
 	}
 
-
-
 	/**
-	 * @param description the description to set
+	 * @param description
+	 *            the description to set
 	 */
 	public void setDescription(String description) {
 		this.description = description;
 	}
 
-
-
 	/**
 	 * @return the id
 	 */
-	public String getId() {
+	public int getId() {
 		return id;
 	}
 
-
-
 	/**
-	 * @param id the id to set
+	 * @param id
+	 *            the id to set
 	 */
-	public void setId(String id) {
+	public void setId(final int id) {
 		this.id = id;
 	}
 
@@ -154,16 +149,17 @@
 
 	@Override
 	public boolean equals(Object obj) {
-		if(obj == null || !(obj instanceof TimeEvent)) {
+		if (obj == null || !(obj instanceof TimeEvent)) {
 			return false;
 		}
-		
+
 		TimeEvent e = (TimeEvent) obj;
-		return e.getId().equals(getId());
+		return e.getId() == getId();
 	}
 
 	/**
-	 * @param showText the showText to set
+	 * @param showText
+	 *            the showText to set
 	 */
 	public void setShowText(boolean showText) {
 		this.showText = showText;
@@ -176,73 +172,59 @@
 		return showText;
 	}
 
-	public long calculateOffsetFromCenter(final long eventDate) {
-		//here's what we start from
-		long millisecondPerUnit = currentTimeBand.getUnit().getMilliseconds();
-		long pixelsPerUnit = currentTimeBand.getPixelsPerUnit();
-		long currentOriginDate = currentTimeBand.getCurrentDate();
-		long currentOriginXPixel = currentTimeBand.getCurrentDateX();
 
-		//what's one pixel in milliseconds?
-		double onePixelInMs = (double) millisecondPerUnit / pixelsPerUnit;
-
-		//calculate difference with current position on timeband
-		long differenceWithEvent = eventDate - currentOriginDate;
-		long pixelValueOnBand = currentOriginXPixel + (long) (differenceWithEvent / onePixelInMs);
-
-		return pixelValueOnBand;
-	}
-	
 	/**
 	 * the main responsible culprit for painting events on the timeband
 	 */
-	public void paint() {
-		currentTimeBand.getBandDiv().appendChild(eventDiv);
-		
-		//the eventDiv will contain both divs, the actual event icon/div display
-		//and the label...
-		eventDiv.appendChild(icon);
-		eventDiv.appendChild(label);
-		
-		
-//		currentTimeBand.getBandDiv().appendChild(label);
-		eventDiv.setClassName(TimelineConstants.EVENT);
-//		icon.setClassName(TimelineConstants.EVENT);
-//		label.setClassName(TimelineConstants.EVENT);
-		
-		//use GXT to wrap our element:
-		El gxtEvent = new El(eventDiv);
-		El gxtIcon = new El(icon);
-		El gxtLabel = new El(label);
-		
-		
-		//setting left position of event holder (icon + text)
-		long leftPixelPosition = calculateOffsetFromCenter(minDate.longValue());
-		gxtEvent.setLeft((int) leftPixelPosition);
-		
-		
-		if(maxDate != null) {
-			long width = calculateOffsetFromCenter(maxDate.longValue()) - leftPixelPosition;
-			gxtIcon.setWidth((int) width);
-			gxtIcon.setStyleName(eventType, true);
-			gxtLabel.setLeft((int) leftPixelPosition); 
-			gxtLabel.setStyleName(TimelineConstants.DURATION_LABEL, true);
+	public synchronized void paint() {
+		if (!isRendered) {
+			currentTimeBand.getBandDiv().appendChild(eventDiv);
+
+			// the eventDiv will contain both divs, the actual event icon/div
+			// display
+			// and the label...
+			eventDiv.appendChild(icon);
+			eventDiv.appendChild(label);
+
+			// currentTimeBand.getBandDiv().appendChild(label);
+			eventDiv.setClassName(TimelineConstants.EVENT);
+			// icon.setClassName(TimelineConstants.EVENT);
+			// label.setClassName(TimelineConstants.EVENT);
+
+			// use GXT to wrap our element:
+			El gxtEvent = new El(eventDiv);
+			El gxtIcon = new El(icon);
+			El gxtLabel = new El(label);
+
+			// setting left position of event holder (icon + text)
+			long leftPixelPosition = TimeConversionUtil.timeToPixel(minDate.longValue(), currentTimeBand);
+			gxtEvent.setLeft((int) leftPixelPosition);
+
+			if (maxDate != null) {
+				long width = TimeConversionUtil.timeToPixel(maxDate.longValue(), currentTimeBand) - leftPixelPosition;
+				gxtIcon.setWidth((int) width);
+				gxtIcon.setStyleName(eventType, true);
+				gxtLabel.setLeft((int) leftPixelPosition);
+				gxtLabel.setStyleName(TimelineConstants.DURATION_LABEL, true);
+			} else {
+				// point in time.
+				gxtLabel.setStyleName(TimelineConstants.POINT_IN_TIME_LABEL, true);
+				// gxtIcon.setWidth(TimelineConstants.POINT_IN_TIME_WIDTH_SPACE);
+				gxtLabel.setLeft((int) leftPixelPosition + TimelineConstants.POINT_IN_TIME_WIDTH_SPACE);
+			}
+
+			// TODO: derive type from database first
+			//
+
+			// set the name of the event
+			label.setInnerText(description);
+			// eventDiv.setPropertyString("style", "left: " + leftOffset);
+			isRendered = true;
 		} else {
-			//point in time.
-			gxtLabel.setStyleName(TimelineConstants.POINT_IN_TIME_LABEL, true);
-			//gxtIcon.setWidth(TimelineConstants.POINT_IN_TIME_WIDTH_SPACE);
-			gxtLabel.setLeft((int) leftPixelPosition + TimelineConstants.POINT_IN_TIME_WIDTH_SPACE);
+			//Log.debug("The event was showing already, so no repaint has occured: (" + getId() + ", " + getDescription() + ")");
 		}
-		
-		//TODO: derive type from database first
-		//
-		
-		//set the name of the event
-		label.setInnerText(description);
-		//eventDiv.setPropertyString("style", "left: " + leftOffset);
-		
 	}
-	
+
 	/**
 	 * @return the eventType
 	 */
@@ -250,28 +232,34 @@
 		return eventType;
 	}
 
-
 	/**
-	 * @param eventType the eventType to set
+	 * @param eventType
+	 *            the eventType to set
 	 */
 	public void setEventType(String eventType) {
 		this.eventType = eventType;
 	}
 
-
 	/**
-	 * @param minDate the minDate to set
+	 * @param minDate
+	 *            the minDate to set
 	 */
 	public void setMinDate(Long minDate) {
 		this.minDate = minDate;
 	}
 
-
 	/**
-	 * @param maxDate the maxDate to set
+	 * @param maxDate
+	 *            the maxDate to set
 	 */
 	public void setMaxDate(Long maxDate) {
 		this.maxDate = maxDate;
 	}
 
+	public void repaint(double zoomRatio) {
+		El element = new El(this.eventDiv);
+		element.setLeft((int) (element.getLeft() * zoomRatio));
+		element.setWidth((int) (element.getWidth() * zoomRatio));
+	}
+
 }

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeScale.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeScale.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeScale.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,111 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+import java.util.HashMap;
+
+import com.allen_sauer.gwt.log.client.Log;
+import com.extjs.gxt.ui.client.core.El;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+
+public class TimeScale {
+	private boolean isRendered = false;
+	private final TimeBand band;
+	private Element scaleBand;
+	HashMap<Integer, Element> paintedTimescaleBands;
+	
+	/**
+	 * A timescale is attached to a timeband
+	 * 
+	 * @param band
+	 */
+	public TimeScale(final TimeBand band) {
+		this.band = band;
+		paintedTimescaleBands = new HashMap<Integer, Element>();
+	}
+
+	/**
+	 * this paints the timescale band on those bits that need painting...
+	 */
+	public void paint() {
+		//check band is rendered, otherwise this is a waste of time
+		if(!band.isRendered()) {
+			return;
+		}
+//	TODO: this is taking too long and rendering for inexitant bands.
+		//disable logging to see if that matters so much at the moment
+		//bearing in mind we will be having less bands over all anyway
+		if (!isRendered) {
+			scaleBand = DOM.createDiv();
+			El gxtScaleBand = new El(scaleBand);
+			band.getBandDiv().appendChild(scaleBand);
+			gxtScaleBand.setStyleName("step-scale-band", true);
+			isRendered = true;
+		}
+
+		// finally render those bits that are visible only
+		paintVisibleScale();
+	}
+
+	private void paintVisibleScale() {
+		long visibleLeft = band.getMinVisibleDate();
+		long visibleRight = band.getMaxVisibleDate();
+
+		// TODO: change this at some point
+		Unit unit = band.getUnit();
+
+		//We do not want to generate all the time scale segments, 
+		//the number of visible segments is number of time 'unit' is in the visible section
+		long numberOfVisibleSegments = (visibleRight - visibleLeft) / unit.getMilliseconds();
+		
+		//first visible segment is going to be located at
+		long firstVisibleSegmentPixel = TimeConversionUtil.timeToPixel(visibleLeft - (visibleLeft % unit.getMilliseconds()), band);
+		
+		//TODO: uncomment all the debug statements and change global logging level to info
+		//Log.debug("Drawing segments for timeband" + band.getId());
+		drawSegments(firstVisibleSegmentPixel, numberOfVisibleSegments);		
+	}
+
+	private synchronized void drawSegments(final long firstVisibleSegmentPixel, final long numberOfVisibleSegments) {
+		El gxtScaleBand = new El(scaleBand);
+		int pixelsPerUnit = band.getPixelsPerUnit();
+		int relativeLeft = (int) firstVisibleSegmentPixel;
+		Log.debug("Drawing segments");
+		for (long ii = 0; ii < numberOfVisibleSegments+1; ii++) {
+			//check segment not already drawn...
+			Integer key = new Integer(relativeLeft);
+			//this bit below needs to be syncrhonised, ie.
+			
+			if (!paintedTimescaleBands.containsKey(key)) {
+				Element un = DOM.createDiv();
+				El gxtUn = new El(un);
+				gxtUn.setWidth(pixelsPerUnit);
+				
+				un.setInnerText(TimeConversionUtil.formatPixelToTime(relativeLeft, band));
+				gxtScaleBand.appendChild(un);
+
+				// set left position:
+				gxtUn.setLeft(relativeLeft);
+				gxtUn.setHeight("100%");
+
+				paintedTimescaleBands.put(key, un);
+			} else {
+				//Log.debug("Segment not drawn as already painted");
+			}
+			relativeLeft += pixelsPerUnit;
+		}
+	}
+	
+	/**
+	 * The easy way is to get rid of everything and repaint
+	 * The slightly more clever way is to actually repaint the existing dom elements. Let's go for more
+	 * clever way for now. It uses more memory though, however, we can try both eventually if need be.
+	 */
+	public void repaint(double zoomRatio) {
+		for(Element tsu : paintedTimescaleBands.values()) {
+			El element = new El(tsu);
+			element.setLeft((int) (element.getLeft() * zoomRatio));
+			
+			//TODO: HERE once repainted need to update all the keys too, the text on the dates and all that
+		}
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimebandRequestWindow.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimebandRequestWindow.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimebandRequestWindow.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,69 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+import com.allen_sauer.gwt.log.client.Log;
+
+/**
+ * This window identifies what is already displayed on the timeline
+ * Perhaps later we send this back to the server, and let the server work out
+ * which bits and pieces each timebands are interested in. 
+ * So still send the full view coordinates, but send that as well.
+ * @author CJBurrell
+ *
+ */
+public class TimebandRequestWindow {
+	private long minDate;
+	private long maxDate;
+	
+	public TimebandRequestWindow(final long initialMin, final long initialMax) {
+		minDate = initialMin;
+		maxDate = initialMax;
+	}
+
+	/**
+	 * Enlarges the minimum window on the left hand-side
+	 * @param minDateRequested the new minDate that the band has received
+	 */
+	public void adjustRange(long minDateRequested, long maxDateRequested) {
+		//Log.debug("Adjusting minimum of received/requested window");
+
+		//adjust minimum: as long as the minimum is before, but the max within range, we're fine to adjust
+		// --------------------<-------$-----<-------$------------------
+		//                  mdr       md     Mdr     MD
+ 		if(minDateRequested < minDate && maxDateRequested >= minDate) {
+			minDate = minDateRequested;
+		}
+	
+		//do the same for the maximum:
+ 		if(maxDateRequested > maxDate && minDateRequested <= maxDate) {
+ 			maxDate = maxDateRequested;
+ 		}
+	}
+	
+	/**
+	 * @return the minDate
+	 */
+	public long getMinDate() {
+		return minDate;
+	}
+
+	/**
+	 * @param minDate the minDate to set
+	 */
+	public void setMinDate(long minDate) {
+		this.minDate = minDate;
+	}
+
+	/**
+	 * @return the maxDate
+	 */
+	public long getMaxDate() {
+		return maxDate;
+	}
+
+	/**
+	 * @param maxDate the maxDate to set
+	 */
+	public void setMaxDate(long maxDate) {
+		this.maxDate = maxDate;
+	}
+}

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/Timeline.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/Timeline.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/Timeline.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -3,125 +3,65 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import net.customware.gwt.presenter.client.EventBus;
+
 import com.allen_sauer.gwt.log.client.Log;
 import com.extjs.gxt.ui.client.core.El;
 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.MouseUpEvent;
-import com.google.gwt.event.dom.client.MouseUpHandler;
 import com.google.gwt.user.client.DOM;
 import com.google.gwt.user.client.Element;
 import com.google.gwt.user.client.ui.Widget;
+import com.tyndalehouse.step.web.client.toolkit.timeline.events.TimelineMouseHandler;
+import com.tyndalehouse.step.web.shared.beans.TimeBandVisibleDate;
+import com.tyndalehouse.step.web.shared.event.TimelineScrollEvent;
 
-
 /**
- * div .step-timeline (step-grab step-letgo)
- * |
- * |
- * - div .step-timeline-container
- *   |
- *   |
- *   - div .step-timeband-container
- *     |
- *     |
- *     - div .step-timeband
- *       |
- *       |
- *       - div . step-scale-band
- *       
+ * div .step-timeline (step-grab step-letgo) | | - div .step-timeline-container
+ * | | - div .step-timeband-container | | - div .step-timeband | | - div .
+ * step-scale-band
+ * 
  * @author CJBurrell
- *
+ * 
  */
 public class Timeline extends Widget {
-	//a timeline has many different bands
-	/** TODO: change treemap, as not in charge of order in this case!
-	 * or change the ids
-	 */
-	//private TreeMap<String, TimeBand> timeBands;
-	private List<TimeBand> timeBands;
-//	private List<String> timeBandIds;
-	
+	private List<TimeBand> timebands;
 	private boolean isHorizontal;
 	private int width;
 	private int height;
 	private Element timelineContainer;
-	
-
 	private Element timelineDiv;
 	private boolean downStatus;
 	private int clientX;
-	private int scrollLeft;
-	
-	
-	public Timeline() {
-		//timeBands = new TreeMap<String, TimeBand>();
-		timeBands = new ArrayList<TimeBand>();
-//		timeBandIds = new ArrayList<String>();
-		
-		
+
+	private final EventBus eventBus;
+	private boolean isRendered = false;
+
+	public Timeline(EventBus eventBus) {
+		this.eventBus = eventBus;
+		timebands = new ArrayList<TimeBand>();
+
 		timelineContainer = DOM.createDiv();
 		timelineContainer.setClassName("step-timeline-container");
-		
+
 		timelineDiv = DOM.createDiv();
 		timelineDiv.setClassName("step-timeline");
 		setElement(timelineDiv);
-		
-		TimelineMouseHandler tmh = new TimelineMouseHandler();
-		
-		addDomHandler(new MouseMoveHandler() {
-			@Override
-			public void onMouseMove(MouseMoveEvent event) {
-				//Log.debug("Mouse was moved above timeline");
-//				EventTarget et =  event.getNativeEvent().getEventTarget();
-//				com.google.gwt.dom.client.Element el = et.cast();
-				handle(event);
-			}
-			
-		}, MouseMoveEvent.getType());
-		addDomHandler(new MouseUpHandler() {
-			@Override
-			public void onMouseUp(MouseUpEvent event) {
-				Log.debug("Mouse was upped");
-//				EventTarget et =  event.getNativeEvent().getEventTarget();
-//				com.google.gwt.dom.client.Element el = et.cast();
-				handle(event);
-			}
-			
-		}, MouseUpEvent.getType());
-	
-		addDomHandler(new MouseDownHandler() {
-			@Override
-			public void onMouseDown(MouseDownEvent event) {
-				Log.debug("Mouse was Down");
-				handle(event);
-			}
-		}, MouseDownEvent.getType());
 
-		addDomHandler(new MouseOutHandler() {
-			@Override
-			public void onMouseOut(MouseOutEvent event) {
-				Log.debug("Mouse was out");
-				handle(event);
-			}
-			
-		}, MouseOutEvent.getType());
+		paint();
+		addMouseHandlers();
+		disableSelection(getElement());		
+	}
 
-		
-		disableSelection(getElement());
-		
-		
-//		addDomHandler(() {
-//			@Override
-//			public void onMouseOut(MouseOutEvent event) {
-//				Log.debug("Mouse was out");
-//				handle(event);
-//			}
-//			
-//		}, MouseOutEvent.getType());
+	// TODO: investigate pushing the handlers in to the handler!!!
+	private void addMouseHandlers() {
+		TimelineMouseHandler tmh = new TimelineMouseHandler(this);
+		addDomHandler(tmh, MouseMoveEvent.getType());
+		addDomHandler(tmh, MouseUpEvent.getType());
+		addDomHandler(tmh, MouseDownEvent.getType());
+		addDomHandler(tmh, MouseOutEvent.getType());
 	}
 
 	private native static void disableSelection(Element e) /*-{
@@ -130,119 +70,146 @@
 		e.style.MozUserSelect = "none";
 	}-*/;
 
-	private void handle(MouseOutEvent event) {
-		// TODO Auto-generated method stub
+	public void handle(MouseOutEvent event) {
 		downStatus = false;
 	}
-	
+
 	public void handle(MouseMoveEvent e) {
-//		EventTarget et =  event.getNativeEvent().getEventTarget();
-//		com.google.gwt.dom.client.Element el = et.cast();				
-		
-		//TODO: customize as a property?
-		TimeBand defaultTimeBand = timeBands.get(0);
+		// TODO: customize as a property?
+		TimeBand defaultTimeBand = timebands.get(0);
 		Unit defaultUnit = defaultTimeBand.getUnit();
-		int defaultPixelsPerUnit = defaultTimeBand.getPixelsPerUnit(); 
-		
-		if(downStatus) {
-			//mouse is down so move the scroll bars on each timeband			
-			//for each timeband, scroll a certain amount... This amount though is relative to the scales
-			//assume timeband 0 is the default
-			for(TimeBand tb : timeBands) {
+		int defaultPixelsPerUnit = defaultTimeBand.getPixelsPerUnit();
+
+		if (downStatus) {
+			// mouse is down so move the scroll bars on each timeband
+			// for each timeband, scroll a certain amount... This amount though
+			// is relative to the scales
+			// assume timeband 0 is the default
+			// at the same time we want to add some new scroll visible event to
+			// allow service layer to update
+			// the events shown if necessary on each timeband
+
+			for (TimeBand tb : timebands) {
 				tb.setScrollLeft(clientX, e.getClientX(), defaultUnit, defaultPixelsPerUnit);
-				Log.debug("About to scroll: " + (clientX - e.getClientX()));
+				//Log.debug("About to scroll: " + (clientX - e.getClientX()));
+
+				// TODO: decide whether we want to filter out some events here
+				// already
+				// to avoid having events flying all over the place...
+				// build the event here scrolling...
+				// TODO: use units here instead?
+			}
+
+			// fire the event and let presenter decide how much of the event
+			// needs to be passed back to the server...
+			//TODO: this needs to  be fired also in the case of window resizing events
+			fireTimelineScrollEvent();
+		}
+	}
+
+	/**
+	 * Both on load and on scroll we are doing an awful lot of looping
+	 * to repaint just in case
+	 * TODO: change this perhaps with a stack of repainting needed
+	 * to ensure that we only repaint those timebands that think they need repainting.
+	 * for example, we don't need to be repainting the whole band for one event
+	 * etc.
+	 */
+	public void fireTimelineScrollEvent() {
+		TimelineScrollEvent tse = new TimelineScrollEvent();
+
+		//calculate only those bits that need requesting! but at the same time
+		//we don't need to wait for the server to redraw timebands
+		for (TimeBand tb : timebands) {
+			try {
+				tb.paint(); //the timeband is rendered, and there are no new events,
+							//so apart from looping through the events which are already rendered
+							//we are only repainting the timescale
 				
+				TimeBandVisibleDate tvd = tb.getOustandingTimebandPeriod();
+				if(!tvd.isNoRequest()) {
+					tse.addTimebandVisibleDate(tvd);
+				} else {
+//					Log.debug("Ignoring timeband request as already have the data");
+				}		
+			} catch (IncapableOfCalculatingRequestWindowException e) {
+				Log.error("Incapable of calculating request window", e);
 			}
-		}	
+		}
+		
+		//check we have something to fire
+		if(tse.getTimebandVisibleDates().size() != 0) {
+			eventBus.fireEvent(tse);
+		} else {
+			//Log.debug("Event not fired, no need for it");
+		}
 	}
-	
+
 	public void handle(MouseUpEvent e) {
 		downStatus = false;
 		new El(timelineDiv).setStyleName("step-letgo", true);
 	}
-	
+
 	public void handle(MouseDownEvent e) {
 		downStatus = true;
 		clientX = e.getClientX();
-		
-		//capture scrollLeft on every timeband
-		for(TimeBand tb : timeBands) {
+
+		// capture scrollLeft on every timeband
+		for (TimeBand tb : timebands) {
 			tb.captureScrollLeft(e);
 		}
-		
-		Log.debug("ClientX " + clientX);
-		//scrollLeft = timelineDiv.getScrollLeft();
-		
-		//change cursor to hand grab
+
+		//Log.debug("ClientX " + clientX);
+
+		// change cursor to hand grab
 		new El(timelineDiv).setStyleName("step-grab", true);
-		
-		//cursor: hand; /* ? */
+
+		// cursor: hand; /* ? */ TODO
 	}
-	
-	
-	
-	@Override
-	protected void onAttach() {
-		super.onAttach();
-		Log.debug("attaching timeline widget");
-	};
-	
-	@Override
-	protected void doAttachChildren() {
-		//not used
-	}
-	
+
 	/**
-	 * call this when the size of the timeline has changed
-	 */
-	public void layout() {
-		//TODO:
-	}
-	
-	/**
 	 * call this when you want to force a repaint
 	 */
 	public synchronized void paint() {
-		if(timelineDiv == null) {
-			//this.getElement().appendChild(timelineDiv);
-			
-		} else {
-			//TODO if called paint again, what do we want to do?
-		}
+		if (!isRendered) {
+			timelineDiv.appendChild(timelineContainer);
 
-		timelineDiv.appendChild(timelineContainer);
-		
-		int relativeTop = 0;
-		for(TimeBand tb : timeBands) {
-			tb.paint(relativeTop);
-			relativeTop += tb.getHeight();
+			int relativeTop = 0;
+			for (TimeBand tb : timebands) {
+				tb.paint(relativeTop);
+				relativeTop += tb.getHeight();
+			}
+
+			// the total relative at this stage is the total height of the
+			// timeline
+			new El(timelineDiv).setHeight(relativeTop);
+			isRendered = true;
 		}
-		
-		//the total relative at this stage is the total height of the timeline
-		new El(timelineDiv).setHeight(relativeTop);
 	}
-	
+
 	public synchronized void addBand(TimeBand band) {
-		timeBands.add(band);		
+		timebands.add(band);
+		band.paint();
 	}
-	
+
 	public void removeBand(String bandId) {
-		timeBands.remove(bandId);
+		timebands.remove(bandId);
 	}
-	
-	public TimeBand getBand(final String bandId) throws TimeBandNotFoundException {
-		//do a linear search - we're not going to have lots of timebands
-		for(TimeBand t : timeBands) {
-			if(t.getId().equals(bandId)) {
+
+	public TimeBand getBand(final int bandId) throws TimeBandNotFoundException {
+		// do a linear search - we're not going to have lots of timebands
+		for (TimeBand t : timebands) {
+			if (t.getId() == bandId) {
 				return t;
 			}
 		}
-		
+
 		throw new TimeBandNotFoundException("Timeband " + bandId + " was not found.");
 	}
 
 	/**
-	 * @param isHorizontal the isHorizontal to set
+	 * @param isHorizontal
+	 *            the isHorizontal to set
 	 */
 	public void setHorizontal(boolean isHorizontal) {
 		this.isHorizontal = isHorizontal;
@@ -256,7 +223,8 @@
 	}
 
 	/**
-	 * @param width the width to set
+	 * @param width
+	 *            the width to set
 	 */
 	public void setWidth(int width) {
 		this.width = width;
@@ -270,7 +238,8 @@
 	}
 
 	/**
-	 * @param height the height to set
+	 * @param height
+	 *            the height to set
 	 */
 	public void setHeight(int height) {
 		this.height = height;
@@ -284,13 +253,31 @@
 	}
 
 	public int getBandCount() {
-		return timeBands.size();
+		return timebands.size();
 	}
-	
+
 	/**
 	 * @return the timelineContainer
 	 */
 	public Element getTimelineContainer() {
 		return timelineContainer;
 	}
+
+	/**
+	 * Zooming is done on a band level, so delegate to timebands
+	 */
+	public void zoomIn() {
+		for(TimeBand tb : timebands) {
+			tb.zoomIn();
+		}
+	}
+
+	/**
+	 * Zooming is done on a band level, so delegate to timebands
+	 */
+	public void zoomOut() {
+		for(TimeBand tb : timebands) {
+			tb.zoomOut();
+		}		
+	}
 }

Deleted: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimelineMouseHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimelineMouseHandler.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimelineMouseHandler.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -1,25 +0,0 @@
-package com.tyndalehouse.step.web.client.toolkit.timeline;
-
-import com.allen_sauer.gwt.log.client.Log;
-import com.google.gwt.event.dom.client.MouseMoveHandler;
-import com.google.gwt.event.shared.GwtEvent;
-
-public class TimelineMouseHandler extends GwtEvent<MouseMoveHandler> {
-
-	public static Type<MouseMoveHandler> TYPE = 
-		new Type<MouseMoveHandler>();
-	
-	@Override
-	public Type<MouseMoveHandler> getAssociatedType() {
-		Log.debug("Type requested from mouse move handler");
-		return TYPE;
-	}
-
-	@Override
-	protected void dispatch(MouseMoveHandler handler) {
-		// TODO Auto-generated method stub
-		Log.debug("Dispatched mousemove handler event");
-		
-	}
-
-}

Copied: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/events/TimelineMouseHandler.java (from rev 29, trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimelineMouseHandler.java)
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/events/TimelineMouseHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/events/TimelineMouseHandler.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,39 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.events;
+
+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.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
+import com.tyndalehouse.step.web.client.toolkit.timeline.Timeline;
+
+public class TimelineMouseHandler implements MouseMoveHandler, MouseUpHandler, MouseDownHandler, MouseOutHandler {
+	private final Timeline timeline;
+
+	public TimelineMouseHandler(Timeline timeline) {
+		this.timeline = timeline;
+	}
+
+	@Override
+	public void onMouseUp(MouseUpEvent event) {
+		timeline.handle(event);
+	}
+
+	@Override
+	public void onMouseDown(MouseDownEvent event) {
+		timeline.handle(event);
+	}
+
+	@Override
+	public void onMouseOut(MouseOutEvent event) {
+		timeline.handle(event);
+	}
+
+	@Override
+	public void onMouseMove(MouseMoveEvent event) {
+		timeline.handle(event);		
+	}
+}


Property changes on: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/events/TimelineMouseHandler.java
___________________________________________________________________
Added: svn:mergeinfo
   + 

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/TimelineView.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/TimelineView.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/TimelineView.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -1,47 +1,35 @@
 package com.tyndalehouse.step.web.client.view;
 
+import net.customware.gwt.presenter.client.EventBus;
+
+import com.google.gwt.event.dom.client.HasClickHandlers;
+import com.google.gwt.user.client.ui.Button;
 import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
 import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
 import com.tyndalehouse.step.web.client.presenter.TimelinePresenter;
-import com.tyndalehouse.step.web.client.toolkit.timeline.ScaleBand;
-import com.tyndalehouse.step.web.client.toolkit.timeline.TimeBand;
-import com.tyndalehouse.step.web.client.toolkit.timeline.TimeEvent;
-import com.tyndalehouse.step.web.client.toolkit.timeline.Unit;
-import com.tyndalehouse.step.web.client.widgets.timeline.TimeLineWidget;
+import com.tyndalehouse.step.web.client.toolkit.timeline.Timeline;
 
 public class TimelineView extends Composite implements TimelinePresenter.Display {
 
-	//@Inject
-	public TimelineView() {
+    private Timeline timeline;
+	private Button zoomOut;
+	private Button zoomIn;
+
+	@Inject
+	public TimelineView(EventBus eventBus) {
         //to do a custom timeline for testing
-        com.tyndalehouse.step.web.client.toolkit.timeline.Timeline testT = 
-        	new com.tyndalehouse.step.web.client.toolkit.timeline.Timeline(
-        			);
-        initWidget(testT);
+		//TODO: change to a provider, lookup Gin/Guice manual to do this...
+		timeline = new Timeline(eventBus);
         
-        //TODO: make the timeline class a factory?
-        TimeBand tb = new TimeBand(testT, "t1");
-        tb.setPixelsPerUnit(50);
-        tb.setHeight(75);
-        tb.setUnit(Unit.YEAR);
-        tb.setCurrentDate(-62220095958093L);
-        TimeEvent te1 = new TimeEvent("e1", "John's ministry and the start of Jesus's", -61249478358093L, -61183987158093L, tb);
-        TimeEvent te2 = new TimeEvent("e2", "Birth of Jesus promised", -62220095958093L, null, tb);
-        TimeEvent te3 = new TimeEvent("e3", "Jesus's minstry in Perea", -61123247958093L, -61118150358093L, tb);
-        tb.addEvent(te1);
-        tb.addEvent(te2);
-        tb.addEvent(te3);
-        testT.addBand(tb);
-
-        
-        TimeBand tb2 = new TimeBand(testT, "t2");
-        tb2.setHeight(50);
-        tb2.setShowScale(true);
-        tb2.setPixelsPerUnit(25);
-        tb2.setUnit(Unit.YEAR);
-        testT.addBand(tb2);
-        
-        testT.paint();
+		FlowPanel fp = new FlowPanel();
+		zoomIn = new Button("+");
+		zoomOut = new Button("-");
+		fp.add(timeline);
+		fp.add(zoomIn);
+		fp.add(zoomOut);
+		initWidget(fp);
 	}
 	
 	@Override
@@ -61,9 +49,18 @@
 		
 	}
 
+	/**
+	 * @return the timeline
+	 */
+	public Timeline getTimeline() {
+		return timeline;
+	}
 
-	@Override
-	public TimeLineWidget getTimelineWidget() {
-		return null; //return simileTimeWidget;
+	public HasClickHandlers getZoomIn() {
+		return zoomIn;
 	}
+
+	public HasClickHandlers getZoomOut() {
+		return zoomOut;
+	}	
 }

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetEventsForDateRangeHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetEventsForDateRangeHandler.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetEventsForDateRangeHandler.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -5,18 +5,17 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.text.SimpleDateFormat;
-import java.util.Date;
 import java.util.List;
 
 import net.customware.gwt.dispatch.server.ActionHandler;
 import net.customware.gwt.dispatch.server.ExecutionContext;
 import net.customware.gwt.dispatch.shared.ActionException;
 
-import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.logging.Log;
 
 import com.google.inject.Inject;
 import com.tyndalehouse.step.web.server.db.DbProvider;
+import com.tyndalehouse.step.web.shared.beans.TimeBandVisibleDate;
 import com.tyndalehouse.step.web.shared.beans.TimelineEventBean;
 import com.tyndalehouse.step.web.shared.command.GetEventsForDateRangeCommand;
 import com.tyndalehouse.step.web.shared.result.GetEventsForDateRangeResult;
@@ -31,8 +30,11 @@
 	}
 
 	@Override
+	//TODO: build a proper sql statement to query all time bands in one go
+	//TODO: this needs to change to take into account the three different types of date precision but for now,
+	//let's get something working
 	public GetEventsForDateRangeResult execute(
-			GetEventsForDateRangeCommand cmd, ExecutionContext arg1)
+			GetEventsForDateRangeCommand event, ExecutionContext arg1)
 			throws ActionException {
 
 		Connection conn = null;
@@ -41,103 +43,43 @@
 		//TODO: do some cleaning up for DB code...
 		try {
 			conn = DbProvider.getConnection();
+			List<TimeBandVisibleDate> timebands = event.getVisbleDates();
 			
-			
-			logger.debug(" Min: " + sdf.format(new Date(cmd.getMinDate())) + 
-					     " Max: " + sdf.format(new Date(cmd.getMaxDate())));
-			
-			
-			//TODO: this needs to change to take into account the three different types of date precision
-			//but for now, let's just get something working.
-			
-			//so say, our we're looking at 1AD - 7AD, what we really want to show, is at least all
+			//so say, we're looking at 1AD - 7AD, what we really want to show, is at least all
 			//those events that are between 1AD and 7AD, so the date of the event if it's a point in time
 			//is going to be between 1 and 7
 			//if it's a duration, then we want the starting point to be before our end point
 			//and the end point of the event to be 
 			StringBuilder sql = new StringBuilder();
 			sql.append("select event_id, from_date, to_date, from_precision, to_precision, name, " +
-					"timeline_id, importance_id, " +
+					"timeband_id, importance_id, " +
 					"certainty, event_type_id from step.event " +
 					"where (from_date between ? and ?" +
 					"   or to_date between ? and ?" +
 					"   or (from_date < ? and to_date > ?))");
-			if(!cmd.isShowDuration()) { 
+			if(!event.isShowDuration()) { 
 				sql.append(" and to_date is null");
 			}
 			
+			sql.append(" and timeband_id = ?");
 			PreparedStatement ps = conn.prepareStatement(sql.toString());
 			
-			//TODO: can probably do this better
-			
-			
-			ps.setLong(1, cmd.getMinDate());
-			ps.setLong(2, cmd.getMaxDate());
-			ps.setLong(3, cmd.getMinDate());
-			ps.setLong(4, cmd.getMaxDate());
-			ps.setLong(5, cmd.getMinDate());
-			ps.setLong(6, cmd.getMaxDate());
-
-			ResultSet rs = ps.executeQuery();
 			GetEventsForDateRangeResult result = new GetEventsForDateRangeResult();
 			
-			//TODO: parse the event in some object, as opposed to just fields like that!
-			//in particular the precision type
-			while(rs.next()) {
-				TimelineEventBean teb = new TimelineEventBean(
-						rs.getInt("event_id"),
-						rs.getLong("from_date"),
-						rs.getLong("to_date"),
-						rs.getString("from_precision"),
-						rs.getString("to_precision"),
-						rs.getString("name"),
-						rs.getInt("timeline_id"),
-						rs.getInt("importance_id"),
-						rs.getString("certainty"),
-						rs.getInt("event_type_id")
-						);
-				logger.debug("Found: " + teb.getName());
-				result.add(teb);
-			}
-			
-			//finally, set the xml representation---
-			//TODO: debate as to whether we want to have all the other stuff in there
-			// at the moment it's just overhead that is not used at all!
-			List<TimelineEventBean> events = result.getEvents();
-			//sb.append("<data>");
-			
-			for(TimelineEventBean teb : events) {
-				StringBuffer sb = new StringBuffer();
-				sb.append("<event ");
-				sb.append("start=\"");
-				sb.append(sdf.format(new Date(teb.getFromDate())));
-				sb.append("\" ");
-
+			for(TimeBandVisibleDate tbvd : timebands) {
+				ps.setLong(1, tbvd.getMinDate());
+				ps.setLong(2, tbvd.getMaxDate());
+				ps.setLong(3, tbvd.getMinDate());
+				ps.setLong(4, tbvd.getMaxDate());
+				ps.setLong(5, tbvd.getMinDate());
+				ps.setLong(6, tbvd.getMaxDate());
+				ps.setInt(7, tbvd.getTimebandId());
 				
-				//now we have the start time, put the end time on it if necessary
-				if(!teb.getToPrecision().equals(("N"))) {
-					sb.append("end=\"");
-					sb.append(sdf.format(new Date(teb.getToDate())));
-					sb.append("\" ");
-
-					//if we have the to date, then it's a duration...
-					sb.append("isDuration=\"true\" ");
-				}
-
-				sb.append("title=\"");
-				sb.append(StringEscapeUtils.escapeJavaScript(teb.getName()));
-				sb.append("\"");
-
-				//will do some crazy xml parsing now just to see it work
-				//but really TODO: need to use a library or something so that we're not just building on the fly...
-				
-				sb.append("></event>");
-				teb.setXml(sb.toString());
+				ResultSet rs = ps.executeQuery();
+				addEventToResult(result, rs);
 			}
-			//sb.append("</data>");
 
-			//result.setXml(sb.toString());
-			
+			logger.debug(String.format("Returning %d events to the client", result.getEvents().size()));
 			return result;			
 		} catch (SQLException e) {
 			logger.error(e);
@@ -151,8 +93,26 @@
 		}
 	}
 
+	private void addEventToResult(GetEventsForDateRangeResult result, ResultSet rs) throws SQLException {
+		//TODO: parse the event in some object, as opposed to just fields like that!
+		//in particular the precision type
+		while(rs.next()) {
+			TimelineEventBean teb = new TimelineEventBean(
+					rs.getInt("event_id"),
+					rs.getLong("from_date"),
+					rs.getObject("to_date") == null ? null : rs.getLong("to_date"),
+					rs.getString("from_precision"),
+					rs.getString("to_precision"),
+					rs.getString("name"),
+					rs.getInt("timeband_id"),
+					rs.getInt("importance_id"),
+					rs.getString("certainty"),
+					rs.getInt("event_type_id")
+					);
+			result.add(teb);
+		}
+	}
 
-
 	//This method is used to determine which type of command this handler serves I believe...
 	@Override
 	public Class<GetEventsForDateRangeCommand> getActionType() {

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineUISetupHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineUISetupHandler.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineUISetupHandler.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -40,11 +40,11 @@
 			//TODO: remove all prepared statements and ensure they are made into
 			//singletons
 			
-			String sqlStatement = 	"select t.TIMELINE_ID, t.TIMELINE_DESCRIPTION, t.timeline_code, " +
+			String sqlStatement = 	"select t.timeband_id, t.timeband_description, t.timeband_code, " +
 									"min(e.FROM_DATE) as min_from_date, max(TO_DATE) as max_to_date, count(event_id) as event_count " +
-									"from step.timeline t, step.event e " +
-									"where t.TIMELINE_ID = e.TIMELINE_ID " +
-									"group by t.timeline_id, t.TIMELINE_DESCRIPTION, t.timeline_code ";
+									"from step.timeband t, step.event e " +
+									"where t.timeband_id = e.timeband_id " +
+									"group by t.timeband_id, t.timeband_description, t.timeband_code ";
 			
 			PreparedStatement ps = conn.prepareStatement(sqlStatement);
 			ResultSet rs = ps.executeQuery();
@@ -55,18 +55,16 @@
 			//review this: perhaps we don't need to send all of this to the UI
 			while(rs.next()) {
 				TimelineBean tb = new TimelineBean(
-						rs.getInt("timeline_id"), 
-						rs.getString("timeline_description"), 
-						rs.getString("timeline_code"));
+						rs.getInt("timeband_id"), 
+						rs.getString("timeband_description"), 
+						rs.getString("timeband_code"));
 				tb.setMinDate(rs.getLong("min_from_date"));
 				tb.setMaxDate(rs.getLong("max_to_date"));
 				tb.setEventCount(rs.getInt("event_count"));
-				
-				logger.debug(String.format("Loaded: %s", tb.getTimelineDescription()));
 				timelines.add(tb);
 			}
-
 			
+			logger.debug(String.format("Returning %d timebands to the client.", timelines.size()));
 			GetTimelineUISetupResult r = new GetTimelineUISetupResult();
 			r.setTimelines(timelines);
 			return r;

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimeBandVisibleDate.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimeBandVisibleDate.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimeBandVisibleDate.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,117 @@
+package com.tyndalehouse.step.web.shared.beans;
+
+import java.io.Serializable;
+
+/**
+ * This object acts as a container of the current display window on an ether.
+ * timebandId identifies the timeband and is associated with a minimum and a maximum
+ * date which are generally used to request things off the database.
+ * @author cjburrell
+ *
+ */
+public class TimeBandVisibleDate implements Serializable {
+
+	/**
+	 * default serial id 
+	 */
+	private static final long serialVersionUID = -7384255321830177509L;
+	
+	/**
+	 * time band id 
+	 */
+	private int timebandId;
+
+	/**
+	 * min date visible on the time band
+	 */
+	private long minDate;
+	
+	/**
+	 * max date visible on the timeband
+	 */
+	private long maxDate;
+	
+	private boolean noRequest;
+	
+
+	private TimeBandVisibleDate() {
+	}
+	
+	public static TimeBandVisibleDate getNoRequest() {
+		TimeBandVisibleDate tvd = new TimeBandVisibleDate();
+		tvd.setNoRequest(true);
+		return tvd;
+	}
+	
+	/**
+	 * so that 
+	 * @param timebandId
+	 * @param minDate
+	 * @param maxDate
+	 */
+	public TimeBandVisibleDate(final int timebandId, final long minDate, final long maxDate) {
+		this.timebandId = timebandId;
+		this.minDate = minDate;
+		this.maxDate = maxDate;
+		noRequest = false;
+	}
+	
+	/**
+	 * @return the timebandId
+	 */
+	public int getTimebandId() {
+		return timebandId;
+	}
+
+	/**
+	 * @return the minDate
+	 */
+	public long getMinDate() {
+		return minDate;
+	}
+
+	/**
+	 * @return the maxDate
+	 */
+	public long getMaxDate() {
+		return maxDate;
+	}
+
+	/**
+	 * @param timebandId the timebandId to set
+	 */
+	public void setTimebandId(final int timebandId) {
+		this.timebandId = timebandId;
+	}
+
+	/**
+	 * @param minDate the minDate to set
+	 */
+	public void setMinDate(long minDate) {
+		this.minDate = minDate;
+	}
+
+	/**
+	 * @param maxDate the maxDate to set
+	 */
+	public void setMaxDate(long maxDate) {
+		this.maxDate = maxDate;
+	}
+
+	/** NoRequest determines whether the values in here should be sent back.
+	 * Perhaps we've got everything we need already, so we don't need to send anything
+	 * back to the server
+	 * @return the noRequest
+	 */
+	public boolean isNoRequest() {
+		return noRequest;
+	}
+
+	/**
+	 * @param noRequest the noRequest to set
+	 */
+	public void setNoRequest(boolean noRequest) {
+		this.noRequest = noRequest;
+	}
+
+}

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimelineBean.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimelineBean.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimelineBean.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -13,40 +13,27 @@
 	 */
 	private static final long serialVersionUID = -1734142151232501392L;
 	private int timelineId;
-	private String timelineDescription;
-	private String timelineCode;
-
-	private long minDate;
-	private long maxDate;
-	private int eventCount;
-	
 	/**
-	 * @return the minDate
+	 * @param timelineId the timelineId to set
 	 */
-	public long getMinDate() {
-		return minDate;
+	public void setTimelineId(int timelineId) {
+		this.timelineId = timelineId;
 	}
 
 	/**
-	 * @param minDate the minDate to set
+	 * @param timelineDescription the timelineDescription to set
 	 */
-	public void setMinDate(long minDate) {
-		this.minDate = minDate;
+	public void setTimelineDescription(String timelineDescription) {
+		this.timelineDescription = timelineDescription;
 	}
 
-	/**
-	 * @return the maxDate
-	 */
-	public long getMaxDate() {
-		return maxDate;
-	}
+	private String timelineDescription;
+//	private String timelineCode;
 
-	/**
-	 * @param maxDate the maxDate to set
-	 */
-	public void setMaxDate(long maxDate) {
-		this.maxDate = maxDate;
-	}
+	private long minDate;
+	private long maxDate;
+	private int eventCount;
+	
 
 	public TimelineBean() {
 		
@@ -55,7 +42,7 @@
 	public TimelineBean(int timelineId, String timelineDescription, String timelineCode) {
 		this.timelineId = timelineId;
 		this.timelineDescription = timelineDescription;
-		this.timelineCode = timelineCode;
+//		this.timelineCode = timelineCode;
 	}
 	
 	/**
@@ -73,12 +60,40 @@
 	}
 
 	/**
-	 * @return the timelineCode
+	 * @return the minDate
 	 */
-	public String getTimelineCode() {
-		return timelineCode;
+	public long getMinDate() {
+		return minDate;
 	}
 
+	/**
+	 * @param minDate the minDate to set
+	 */
+	public void setMinDate(long minDate) {
+		this.minDate = minDate;
+	}
+
+	/**
+	 * @return the maxDate
+	 */
+	public long getMaxDate() {
+		return maxDate;
+	}
+
+	/**
+	 * @param maxDate the maxDate to set
+	 */
+	public void setMaxDate(long maxDate) {
+		this.maxDate = maxDate;
+	}
+
+	//	/**
+//	 * @return the timelineCode
+//	 */
+//	public String getTimelineCode() {
+//		return timelineCode;
+//	}
+
 	public void setEventCount(int eventCount) {
 		this.eventCount = eventCount;
 	}

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimelineEventBean.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimelineEventBean.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/beans/TimelineEventBean.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -16,23 +16,11 @@
 	private String certainty;
 	private int eventTypeId;
 
-	/**
-	 * @return the xmlRepresentation
-	 */
-	public String getXmlRepresentation() {
-		return xmlRepresentation;
-	}
-
-	/**
-	 * @param xmlRepresentation the xmlRepresentation to set
-	 */
-	public void setXmlRepresentation(String xmlRepresentation) {
-		this.xmlRepresentation = xmlRepresentation;
-	}
-
 	private String name;
-	private String xmlRepresentation;
+	private int timelineId;
 
+	
+
 	//for serialization
 	public TimelineEventBean() {
 		
@@ -61,10 +49,10 @@
 				this.toDate = toDate;
 				this.fromPrecision = fromPrecision;
 				this.toPrecision = toPrecision;
+				this.timelineId = timelineId;
 				this.certainty = certainty;
 				this.eventTypeId = eventTypeId;
 				this.name = name;
-		
 	}
 	
 	/**
@@ -179,7 +167,17 @@
 		return name;
 	}
 
-	public void setXml(String xmlRepresentation) {
-		this.xmlRepresentation = xmlRepresentation;		
+	/**
+	 * @return the timelineId
+	 */
+	public int getTimelineId() {
+		return timelineId;
 	}
+
+	/**
+	 * @param timelineId the timelineId to set
+	 */
+	public void setTimelineId(int timelineId) {
+		this.timelineId = timelineId;
+	}
 }

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetEventsForDateRangeCommand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetEventsForDateRangeCommand.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetEventsForDateRangeCommand.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -1,20 +1,45 @@
-	package com.tyndalehouse.step.web.shared.command;
+package com.tyndalehouse.step.web.shared.command;
 
+import java.util.List;
+
 import net.customware.gwt.dispatch.shared.Action;
 
+import com.tyndalehouse.step.web.shared.beans.TimeBandVisibleDate;
 import com.tyndalehouse.step.web.shared.result.GetEventsForDateRangeResult;
 
 public class GetEventsForDateRangeCommand  implements Action<GetEventsForDateRangeResult> {
-
 	/**
-	 * 
+	 * default uid
 	 */
 	private static final long serialVersionUID = 5781027650600417430L;
-	private Long minDate;
-	private Long maxDate;
+	
+	/**
+	 * whether to retrieve durations (this is a DEBUG flag really)
+	 */
 	private boolean showDuration = true;
+	
+	/**
+	 * the list of timebands and the times that are currently showing
+	 */
+	private List<TimeBandVisibleDate> visbleDates;
 
 	/**
+	 * default constructor that should be used
+	 * @param visbleDates
+	 */
+	public GetEventsForDateRangeCommand(List<TimeBandVisibleDate> visbleDates) {
+		this.visbleDates = visbleDates;
+		
+	}
+	
+	/**
+	 * Used for serialization
+	 */
+	public GetEventsForDateRangeCommand() {
+		
+	}
+
+	/**
 	 * @return the showDuration
 	 */
 	public boolean isShowDuration() {
@@ -28,31 +53,18 @@
 		this.showDuration = showDuration;
 	}
 
+
 	/**
-	 * @return the minDate
+	 * @return the visbleDates
 	 */
-	public Long getMinDate() {
-		return minDate;
+	public List<TimeBandVisibleDate> getVisbleDates() {
+		return visbleDates;
 	}
 
 	/**
-	 * @return the maxDate
+	 * @param visbleDates the visbleDates to set
 	 */
-	public Long getMaxDate() {
-		return maxDate;
-	}
-
-
-	public GetEventsForDateRangeCommand(Long minDate, Long maxDate) {
-		this.minDate = minDate;
-		this.maxDate = maxDate;
-		
-	}
-	
-	//leaving this cos it gets serialized I believe...
-	public GetEventsForDateRangeCommand() {
-		
-	}
-	
-	
+	public void setVisbleDates(List<TimeBandVisibleDate> visbleDates) {
+		this.visbleDates = visbleDates;
+	}	
 }

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/event/TimelineScrollEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/event/TimelineScrollEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/event/TimelineScrollEvent.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,53 @@
+package com.tyndalehouse.step.web.shared.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.shared.beans.TimeBandVisibleDate;
+import com.tyndalehouse.step.web.shared.eventhandler.TimelineScrollEventHandler;
+
+public class TimelineScrollEvent extends GwtEvent<TimelineScrollEventHandler>{
+	public static Type<TimelineScrollEventHandler> TYPE = new Type<TimelineScrollEventHandler>();
+	private List<TimeBandVisibleDate> timebandVisibleDates;
+	
+	public TimelineScrollEvent() {
+		timebandVisibleDates = new ArrayList<TimeBandVisibleDate>();
+	}
+
+
+	public void addTimebandVisibleDate(int timebandId, long minDate, long maxDate) {
+		TimeBandVisibleDate visibleDate = new TimeBandVisibleDate(timebandId, minDate, maxDate);
+		addTimebandVisibleDate(visibleDate);
+	}
+	
+	public void addTimebandVisibleDate(final TimeBandVisibleDate visibleDate) {
+		if(!visibleDate.isNoRequest()) {
+			timebandVisibleDates.add(visibleDate);
+		}
+	}
+	
+	/**
+	 * @param timebandVisibleDates the timebandVisibleDates to set
+	 */
+	public void setTimebandVisibleDates(List<TimeBandVisibleDate> timebandVisibleDates) {
+		this.timebandVisibleDates = timebandVisibleDates;
+	}
+
+	/**
+	 * @return the timebandVisibleDates
+	 */
+	public List<TimeBandVisibleDate> getTimebandVisibleDates() {
+		return timebandVisibleDates;
+	}	
+	
+	@Override
+	protected void dispatch(TimelineScrollEventHandler handler) {
+		handler.onScroll(this);	
+	}
+
+	@Override
+	public Type<TimelineScrollEventHandler> getAssociatedType() {
+		return TYPE;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/eventhandler/TimelineScrollEventHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/eventhandler/TimelineScrollEventHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/eventhandler/TimelineScrollEventHandler.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -0,0 +1,8 @@
+package com.tyndalehouse.step.web.shared.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.shared.event.TimelineScrollEvent;
+
+public interface TimelineScrollEventHandler  extends EventHandler {
+	public void onScroll(TimelineScrollEvent event);
+}

Modified: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetEventsForDateRangeResult.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetEventsForDateRangeResult.java	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetEventsForDateRangeResult.java	2009-12-07 22:47:44 UTC (rev 32)
@@ -10,10 +10,9 @@
 public class GetEventsForDateRangeResult implements Result {
 
 	private List<TimelineEventBean> events = new ArrayList<TimelineEventBean>();
-	private String xml;
 	
 	/**
-	 * 
+	 * default serial id 
 	 */
 	private static final long serialVersionUID = 7118668612721569823L;
 
@@ -36,21 +35,4 @@
 	public void setEvents(List<TimelineEventBean> events) {
 		this.events = events;
 	}
-
-	/**
-	 * @param xml the xml to set
-	 */
-	public void setXml(String xml) {
-		this.xml = xml;
-	}
-
-	/**
-	 * @return the xml
-	 */
-	public String getXml() {
-		return xml;
-	}
-	
-	
-	
 }

Modified: trunk/step-web-app/war/css/step.css
===================================================================
--- trunk/step-web-app/war/css/step.css	2009-11-29 22:54:43 UTC (rev 31)
+++ trunk/step-web-app/war/css/step.css	2009-12-07 22:47:44 UTC (rev 32)
@@ -54,6 +54,7 @@
 	list-style-type: none;
 	z-index: 100;
 	/* height: 100%; */
+
 }
 
 
@@ -78,7 +79,7 @@
 
 .step-timeline-pointInTime {
 	display:inline;
-	background-image: url("/step/step-timeline/images/blue-circle.png");
+	background-image: url("/step/images/blue-circle.png");
 	width: 10px;
 	border: none;
 	background-repeat: no-repeat;
@@ -86,7 +87,7 @@
 }
 
 .step-time-point-in-time-label {
-	background-image: url("/step/step-timeline/images/blue-circle.png");
+	background-image: url("/step/images/blue-circle.png");
 	display:inline;
 	background-repeat: no-repeat;
 	background-position: left;




More information about the Tynstep-svn mailing list