[Tynstep-svn] r120 - in trunk/step-web-app/src/main/java/com/tyndalehouse/step/web: . client client/common client/event client/eventhandler client/gin client/presenter client/service client/service/eventbus client/service/refdata client/toolkit client/toolkit/scripture client/toolkit/timeline client/toolkit/timeline/components client/toolkit/timeline/events client/toolkit/timeline/exceptions client/toolkit/timeline/helpers client/view server server/common server/db server/db/framework server/db/timeline server/guice server/handler server/handler/util server/handler/util/passage server/jsword server/jsword/com server/jsword/com/tyndalehouse server/jsword/com/tyndalehouse/step server/jsword/com/tyndalehouse/step/web shared shared/command shared/common shared/common/maps shared/common/scripturelookup shared/common/timeline shared/result shared/scripture shared/timeline

ChrisBurrell at crosswire.org ChrisBurrell at crosswire.org
Wed Apr 14 15:11:51 MST 2010


Author: ChrisBurrell
Date: 2010-04-14 15:11:51 -0700 (Wed, 14 Apr 2010)
New Revision: 120

Added:
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/StepEntryPoint.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/common/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/common/CachingDispatchAsync.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/BookSelectedEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/DictionaryDefinitionFoundEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/LemmaClickedEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/ModuleChangeEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/ScriptureChangeEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/TimebandListUpdateRequiredEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/TimelineScrollEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/UserInterestInBandEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/VersionChangeEvent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/BookSelectedEventHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/DictionaryDefinitionFoundHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/LemmaClickedEventHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/ModuleChangeEventHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/ScriptureChangeEventHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/TimebandListUpdateRequiredEventHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/TimelineScrollEventHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/UserInterestInBandEventHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/VersionChangeEventHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/gin/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/gin/StepClientModule.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/gin/StepInjector.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/AppPresenter.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/HistoryModulePresenter.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ModuleSelectorPresenter.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ScripturePresenter.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ScriptureSelectorPresenter.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/StepPresenter.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/TimebandListPresenter.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/service/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/eventbus/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/eventbus/StepEventBusImpl.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/refdata/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/refdata/ModuleName.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/refdata/ModuleRefData.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/HasSource.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/HtmlList.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/SimpleListBox.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/SourceListBox.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/scripture/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/scripture/ScriptureDisplayConstants.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/scripture/VerseLabel.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TapeTrack.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/TimeEventDescriptor.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/Timeband.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/toolkit/timeline/components/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/Orientation.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/TimebandRequestWindow.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/TimelineConstants.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/client/toolkit/timeline/exceptions/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/CannotDeleteEventException.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/IncapableOfCalculatingRequestWindowException.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/TimeBandNotFoundException.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/UnknownFiredElement.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/CurrentBandStats.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/TimeConversionUtil.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/painters/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/HistoryModuleView.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ModuleSelectorView.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ScriptureSelectorView.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ScriptureView.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/StepView.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/TimebandListView.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/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/AbstractStepHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/ConfigNotLoadedException.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/ConfigProvider.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/JSwordConstants.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/MalformedStepQueryException.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/Query.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/QueryImpl.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/ResultSetProcessor.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQuery.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunner.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunnerImpl.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/UnableToRunQueryException.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimeBandVisibleDateProcessor.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginDbBean.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginProcessor.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineSetupDataProcessor.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/CustomDispatchServiceServlet.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/DispatchServletModule.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/LogProvider.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/MyGuiceServletConfig.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/ServerModule.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetAvailableBibleVersionsHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetBibleBooksHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetCurrentBibleTextHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetDictionaryDefinitionHandler.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/GetLocationsHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineOriginForScriptureHandler.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/server/handler/InstallJswordModuleHandler.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/util/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/StrongMorphMap.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/ConfigurableHTMLConverter.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/XSLTProperty.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/com/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/step/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/step/web/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/com/tyndalehouse/step/web/server/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/BooksRequiredType.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetAvailableBibleVersionsCommand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetBibleBooksCommand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetCurrentBibleTextCommand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetDictionaryDefinitionCommand.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/command/GetLocationsCommand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetTimelineOriginForScriptureCommand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetTimelineUISetupCommand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/InstallJswordModuleCommand.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/GeoLocation.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/GeoLocationType.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/LatLong.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/scripturelookup/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/scripturelookup/BibleTextLookupType.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimeBandVisibleDate.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimelineBean.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimelineEventBean.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetAvailableBibleVersionsResult.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetBibleBooksCommandResult.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetCurrentBibleTextResult.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetDictionaryDefinitionResult.java
   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/GetLocationsResult.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetTimelineOriginForScriptureResult.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetTimelineUISetupResult.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/InstallJswordModuleResult.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Milestone.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Note.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/OSISConstants.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Passage.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Text.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/TextualElement.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Title.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/TransChange.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Verse.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/VerseContent.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Word.java
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/timeline/
   trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/timeline/Unit.java
Log:
committing the core code

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/StepEntryPoint.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/StepEntryPoint.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/StepEntryPoint.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,32 @@
+package com.tyndalehouse.step.web.client;
+
+import com.google.gwt.core.client.EntryPoint;
+import com.google.gwt.core.client.GWT;
+import com.google.gwt.user.client.ui.RootPanel;
+import com.tyndalehouse.step.web.client.gin.StepInjector;
+import com.tyndalehouse.step.web.client.presenter.AppPresenter;
+
+/**
+ * Entry point to the one and only application page
+ * 
+ * @author cjburrell
+ * 
+ */
+public class StepEntryPoint implements EntryPoint {
+
+	/**
+	 * Main step injector
+	 */
+	private final StepInjector injector = GWT.create(StepInjector.class);
+
+	/**
+	 * Entry point to the Step application
+	 */
+	public void onModuleLoad() {
+		final AppPresenter appPresenter = injector.getAppPresenter();
+		appPresenter.go(RootPanel.get());
+
+		// injector.getPlaceManager().fireCurrentPlace();
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/common/CachingDispatchAsync.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/common/CachingDispatchAsync.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/common/CachingDispatchAsync.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,92 @@
+package com.tyndalehouse.step.web.client.common;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import net.customware.gwt.dispatch.client.DispatchAsync;
+import net.customware.gwt.dispatch.shared.Action;
+import net.customware.gwt.dispatch.shared.Result;
+
+import com.google.gwt.user.client.rpc.AsyncCallback;
+import com.google.inject.Inject;
+
+//TODO: investigate the user of this client side cache
+/**
+ * Dispatcher which support caching of data in memory
+ * 
+ */
+public class CachingDispatchAsync implements DispatchAsync {
+	/**
+	 * 
+	 */
+	private final Map<Action<Result>, Result> cache = new HashMap<Action<Result>, Result>();
+
+	/**
+	 * The default dispatcher
+	 */
+	private final DispatchAsync dispatcher;
+
+	/**
+	 * The default constructor
+	 * 
+	 * @param dispatcher uses the default dispatcher
+	 */
+	@Inject
+	public CachingDispatchAsync(final DispatchAsync dispatcher) {
+		this.dispatcher = dispatcher;
+	}
+
+	/**
+	 * Clear the cache
+	 */
+	public void clear() {
+		cache.clear();
+	}
+
+	/**
+	 * This method is a simple wrapper around the DispatchAsync class at the
+	 * moment
+	 * 
+	 * @param <A> Action implementation
+	 * @param <R> Result implementation
+	 * @param action the action
+	 * @param callback the callback
+	 * @see net.customware.gwt.dispatch.client.DispatchAsync#execute(A,
+	 *      com.google.gwt.user.client.rpc.AsyncCallback)
+	 */
+	public <A extends Action<R>, R extends Result> void execute(final A action,
+			final AsyncCallback<R> callback) {
+		dispatcher.execute(action, callback);
+	}
+
+	/**
+	 * 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
+	 * @param action the action
+	 * @param callback the callback
+	 */
+	@SuppressWarnings("unchecked")
+	public <A extends Action<R>, R extends Result> void executeWithCache(final A action,
+			final AsyncCallback<R> callback) {
+		final Result r = cache.get(action);
+
+		if (r != null) {
+			callback.onSuccess((R) r);
+		} else {
+			dispatcher.execute(action, new AsyncCallback<R>() {
+
+				public void onFailure(final Throwable caught) {
+					callback.onFailure(caught);
+				}
+
+				public void onSuccess(final R result) {
+					cache.put((Action) action, (Result) result);
+					callback.onSuccess(result);
+				}
+			});
+		}
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/BookSelectedEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/BookSelectedEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/BookSelectedEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,32 @@
+package com.tyndalehouse.step.web.client.event;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.client.eventhandler.BookSelectedEventHandler;
+
+/**
+ * The user has selected a book on the UI, and this is being fired to the
+ * DefaultEventBus
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class BookSelectedEvent extends GwtEvent<BookSelectedEventHandler> {
+
+	/**
+	 * The default Type Handler Type is parameterized by the handler type in
+	 * order to make the addHandler method type safe.
+	 */
+	private static Type<BookSelectedEventHandler> TYPE = new Type<BookSelectedEventHandler>();
+
+	@Override
+	public Type<BookSelectedEventHandler> getAssociatedType() {
+		return TYPE;
+	}
+
+	@Override
+	protected void dispatch(final BookSelectedEventHandler handler) {
+		handler.onBookSelected(this);
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/DictionaryDefinitionFoundEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/DictionaryDefinitionFoundEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/DictionaryDefinitionFoundEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,59 @@
+package com.tyndalehouse.step.web.client.event;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.client.eventhandler.DictionaryDefinitionFoundHandler;
+
+/**
+ * The dictionary definition found event. This is fired when the server has
+ * responded with a dictionary definition and different parts of the system may
+ * require notification of it.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class DictionaryDefinitionFoundEvent extends GwtEvent<DictionaryDefinitionFoundHandler> {
+	/**
+	 * The default Type Handler Type is parameterized by the handler type in
+	 * order to make the addHandler method type safe.
+	 */
+	private static Type<DictionaryDefinitionFoundHandler> TYPE = new Type<DictionaryDefinitionFoundHandler>();
+
+	/**
+	 * the definition that was retrieved
+	 */
+	private String definition;
+
+	/**
+	 * default constructor
+	 * 
+	 * @param defintion this is the definition that was retrieved from the
+	 *            server
+	 */
+	public DictionaryDefinitionFoundEvent(final String defintion) {
+		this.definition = defintion;
+	}
+
+	@Override
+	public Type<DictionaryDefinitionFoundHandler> getAssociatedType() {
+		return TYPE;
+	}
+
+	/**
+	 * @return the definition
+	 */
+	public String getDefinition() {
+		return definition;
+	}
+
+	/**
+	 * @param definition the definition to set
+	 */
+	public void setDefinition(final String definition) {
+		this.definition = definition;
+	}
+
+	@Override
+	protected void dispatch(final DictionaryDefinitionFoundHandler handler) {
+		handler.onDefinitionFound(this);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/LemmaClickedEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/LemmaClickedEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/LemmaClickedEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,59 @@
+package com.tyndalehouse.step.web.client.event;
+
+import java.util.List;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.client.eventhandler.LemmaClickedEventHandler;
+
+/**
+ * This event is fired when a portion of scripture tagged with 1 or more lemma
+ * (strong number for e.g.) has been clicked. The event contains details of the
+ * lemmas references.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class LemmaClickedEvent extends GwtEvent<LemmaClickedEventHandler> {
+	/**
+	 * Type of event
+	 */
+	public static Type<LemmaClickedEventHandler> TYPE = new Type<LemmaClickedEventHandler>();
+	/**
+	 * The default Type Handler Type is parameterized by the handler type in
+	 * order to make the addHandler method type safe.
+	 */
+	private List<String> lemma;
+
+	/**
+	 * constructing the event with a list of lemmas
+	 * 
+	 * @param lemmas the list of lemmas that were clicked upon
+	 */
+	public LemmaClickedEvent(final List<String> lemmas) {
+		this.lemma = lemmas;
+	}
+
+	@Override
+	public Type<LemmaClickedEventHandler> getAssociatedType() {
+		return TYPE;
+	}
+
+	/**
+	 * @return the lemma
+	 */
+	public List<String> getLemma() {
+		return lemma;
+	}
+
+	/**
+	 * @param lemma the lemma to set
+	 */
+	public void setLemma(final List<String> lemma) {
+		this.lemma = lemma;
+	}
+
+	@Override
+	protected void dispatch(final LemmaClickedEventHandler handler) {
+		handler.onLemmaClicked(this);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/ModuleChangeEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/ModuleChangeEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/ModuleChangeEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,75 @@
+package com.tyndalehouse.step.web.client.event;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.client.eventhandler.ModuleChangeEventHandler;
+
+/**
+ * Event is fired when part of the module definition (module, sub module, depth)
+ * has been changed
+ * 
+ * @author cjburrell
+ * 
+ */
+public class ModuleChangeEvent extends GwtEvent<ModuleChangeEventHandler> {
+	/**
+	 * The default Type Handler Type is parameterized by the handler type in
+	 * order to make the addHandler method type safe.
+	 */
+	private static Type<ModuleChangeEventHandler> TYPE = new Type<ModuleChangeEventHandler>();
+
+	/** newly selected depth of stud */
+	private final String newDepth;
+	/** newly selected module */
+	private final String newModule;
+	/** newly selected submodule */
+	private final String newSubModule;
+
+	/**
+	 * creates an event alerting of the new chosen combination of
+	 * module/sub-module/depth
+	 * 
+	 * @param newModule new module
+	 * @param newSubModule new sub module
+	 * @param newDepth new depth of study
+	 */
+	public ModuleChangeEvent(final String newModule, final String newSubModule,
+		final String newDepth) {
+		this.newModule = newModule;
+		this.newSubModule = newSubModule;
+		this.newDepth = newDepth;
+	}
+
+	@Override
+	public Type<ModuleChangeEventHandler> getAssociatedType() {
+		return TYPE;
+	}
+
+	/**
+	 * 
+	 * @return the depth
+	 */
+	public String getNewDepth() {
+		return newDepth;
+	}
+
+	/**
+	 * @return the new module
+	 */
+	public String getNewModule() {
+		return newModule;
+	}
+
+	/**
+	 * 
+	 * @return the new sub module
+	 */
+	public String getNewSubModule() {
+		return newSubModule;
+	}
+
+	@Override
+	protected void dispatch(final ModuleChangeEventHandler handler) {
+		handler.onModuleChange(this);
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/ScriptureChangeEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/ScriptureChangeEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/ScriptureChangeEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,53 @@
+package com.tyndalehouse.step.web.client.event;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.client.eventhandler.ScriptureChangeEventHandler;
+
+/**
+ * Scripture change is fired when the scripture viewed on the screen is
+ * requested to be different
+ * 
+ * @author cjburrell
+ * 
+ */
+public class ScriptureChangeEvent extends GwtEvent<ScriptureChangeEventHandler> {
+	/**
+	 * The default Type Handler Type is parameterized by the handler type in
+	 * order to make the addHandler method type safe.
+	 */
+	// TODO: remove this type into an abstract layer
+	public static Type<ScriptureChangeEventHandler> TYPE = new Type<ScriptureChangeEventHandler>();
+
+	/**
+	 * This is the new reference that is being fired.
+	 */
+	private final String newReference;
+
+	/**
+	 * Constructor to create a scripture change even with a biblical reference
+	 * 
+	 * @param newReference the new reference that has been chosen by the user
+	 */
+	public ScriptureChangeEvent(final String newReference) {
+		this.newReference = newReference;
+	}
+
+	@Override
+	public Type<ScriptureChangeEventHandler> getAssociatedType() {
+		return TYPE;
+	}
+
+	/**
+	 * @return the new biblical reference that has been selected
+	 */
+	public String getNewReference() {
+		return newReference;
+	}
+
+	@Override
+	protected void dispatch(final ScriptureChangeEventHandler handler) {
+		handler.onScriptureChange(this);
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/TimebandListUpdateRequiredEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/TimebandListUpdateRequiredEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/TimebandListUpdateRequiredEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,60 @@
+package com.tyndalehouse.step.web.client.event;
+
+import java.util.List;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.client.eventhandler.TimebandListUpdateRequiredEventHandler;
+import com.tyndalehouse.step.web.client.toolkit.timeline.helpers.CurrentBandStats;
+
+/**
+ * Event signalling that the timebands have been changed and an update is
+ * required from any component keeping track of counts
+ * 
+ * @author cjburrell
+ * 
+ */
+public class TimebandListUpdateRequiredEvent extends
+	GwtEvent<TimebandListUpdateRequiredEventHandler> {
+
+	/**
+	 * The default Type Handler Type is parameterized by the handler type in
+	 * order to make the addHandler method type safe.
+	 */
+	public static Type<TimebandListUpdateRequiredEventHandler> TYPE = new Type<TimebandListUpdateRequiredEventHandler>();
+
+	/**
+	 * List of new statistics, one for each band
+	 */
+	private final List<CurrentBandStats> stats;
+
+	/**
+	 * The timeline is passed in, so that the timeband list can know what the
+	 * new values are
+	 * 
+	 * @param stats timeline to be passed in
+	 */
+	public TimebandListUpdateRequiredEvent(final List<CurrentBandStats> stats) {
+		this.stats = stats;
+
+	}
+
+	@Override
+	public Type<TimebandListUpdateRequiredEventHandler> getAssociatedType() {
+		// TODO Auto-generated method stub
+		return TYPE;
+	}
+
+	/**
+	 * @return the stats
+	 */
+	public List<CurrentBandStats> getTimelineStats() {
+		return stats;
+	}
+
+	@Override
+	protected void dispatch(final TimebandListUpdateRequiredEventHandler handler) {
+		handler.onTimebandListRequiringUpdate(this);
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/TimelineScrollEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/TimelineScrollEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/TimelineScrollEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,85 @@
+package com.tyndalehouse.step.web.client.event;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.client.eventhandler.TimelineScrollEventHandler;
+import com.tyndalehouse.step.web.shared.common.timeline.TimeBandVisibleDate;
+
+/**
+ * Event signalling the timeline has been scrolled. This event contains the list
+ * of timebands, and the portions of those that need updating
+ * 
+ * @author cjburrell
+ * 
+ */
+public class TimelineScrollEvent extends GwtEvent<TimelineScrollEventHandler> {
+	/**
+	 * The default Type Handler Type is parameterized by the handler type in
+	 * order to make the addHandler method type safe.
+	 */
+	public static Type<TimelineScrollEventHandler> TYPE = new Type<TimelineScrollEventHandler>();
+
+	/**
+	 * list of requests to the server on which portions of which bands need to
+	 * be updated
+	 */
+	private List<TimeBandVisibleDate> timebandVisibleDates;
+
+	/**
+	 * default constructor
+	 */
+	public TimelineScrollEvent() {
+		timebandVisibleDates = new ArrayList<TimeBandVisibleDate>();
+	}
+
+	/**
+	 * adds a timeband and the portion of time that needs updating
+	 * 
+	 * @param timebandId the timeband id
+	 * @param minDate the minimum date
+	 * @param maxDate the maximum date
+	 */
+	public void addTimebandVisibleDate(final int timebandId, final long minDate, final long maxDate) {
+		final TimeBandVisibleDate visibleDate = new TimeBandVisibleDate(timebandId, minDate,
+			maxDate);
+		addTimebandVisibleDate(visibleDate);
+	}
+
+	/**
+	 * adds a @see {@link TimeBandVisibleDate} to the event
+	 * 
+	 * @param visibleDate the TimeBandVisibleDate object containing details of
+	 *            which parts of the timeband (min, max) need updating.
+	 */
+	public void addTimebandVisibleDate(final TimeBandVisibleDate visibleDate) {
+		if (!visibleDate.isNoRequest()) {
+			timebandVisibleDates.add(visibleDate);
+		}
+	}
+
+	@Override
+	public Type<TimelineScrollEventHandler> getAssociatedType() {
+		return TYPE;
+	}
+
+	/**
+	 * @return the timebandVisibleDates
+	 */
+	public List<TimeBandVisibleDate> getTimebandVisibleDates() {
+		return timebandVisibleDates;
+	}
+
+	/**
+	 * @param timebandVisibleDates the timebandVisibleDates to set
+	 */
+	public void setTimebandVisibleDates(final List<TimeBandVisibleDate> timebandVisibleDates) {
+		this.timebandVisibleDates = timebandVisibleDates;
+	}
+
+	@Override
+	protected void dispatch(final TimelineScrollEventHandler handler) {
+		handler.onScroll(this);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/UserInterestInBandEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/UserInterestInBandEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/UserInterestInBandEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,64 @@
+package com.tyndalehouse.step.web.client.event;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.client.eventhandler.UserInterestInBandEventHandler;
+
+/**
+ * Event signalling the user is interested or not interested in a new timeband
+ * 
+ * @author cjburrell
+ * 
+ */
+public class UserInterestInBandEvent extends GwtEvent<UserInterestInBandEventHandler> {
+	/**
+	 * The default Type Handler Type is parameterized by the handler type in
+	 * order to make the addHandler method type safe.
+	 */
+	public static Type<UserInterestInBandEventHandler> TYPE = new Type<UserInterestInBandEventHandler>();
+
+	/**
+	 * the band the user has selected to choose or dismiss
+	 */
+	private final int bandId;
+
+	/**
+	 * whether the user wants to see the band or not
+	 */
+	private final Boolean isOfInterest;
+
+	/**
+	 * creates the event
+	 * 
+	 * @param bandId the band that the user selected
+	 * @param isOfInterest whether the user is interested in it or not
+	 */
+	public UserInterestInBandEvent(final int bandId, final Boolean isOfInterest) {
+		this.bandId = bandId;
+		this.isOfInterest = isOfInterest;
+	}
+
+	@Override
+	public Type<UserInterestInBandEventHandler> getAssociatedType() {
+		return TYPE;
+	}
+
+	/**
+	 * @return the bandId
+	 */
+	public int getBandId() {
+		return bandId;
+	}
+
+	/**
+	 * @return the isOfInterest
+	 */
+	public Boolean isOfInterest() {
+		return isOfInterest;
+	}
+
+	@Override
+	protected void dispatch(final UserInterestInBandEventHandler handler) {
+		handler.onUserInterestedInBand(this);
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/VersionChangeEvent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/VersionChangeEvent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/event/VersionChangeEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,29 @@
+package com.tyndalehouse.step.web.client.event;
+
+import com.google.gwt.event.shared.GwtEvent;
+import com.tyndalehouse.step.web.client.eventhandler.VersionChangeEventHandler;
+
+/**
+ * Event signalling a change of bible version of the UI
+ * 
+ * @author cjburrell
+ * 
+ */
+public class VersionChangeEvent extends GwtEvent<VersionChangeEventHandler> {
+	/**
+	 * The default Type Handler Type is parameterized by the handler type in
+	 * order to make the addHandler method type safe.
+	 */
+	public static Type<VersionChangeEventHandler> TYPE = new Type<VersionChangeEventHandler>();
+
+	@Override
+	public Type<VersionChangeEventHandler> getAssociatedType() {
+		return TYPE;
+	}
+
+	@Override
+	protected void dispatch(final VersionChangeEventHandler handler) {
+		handler.onVersionChange(this);
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/BookSelectedEventHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/BookSelectedEventHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/BookSelectedEventHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,22 @@
+package com.tyndalehouse.step.web.client.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.client.event.BookSelectedEvent;
+
+/**
+ * Contract for any handler wanting to handle a BookSelectedEvent In particular
+ * this means handling a click for e.g. on the UI in the list of bible books
+ * (Genesis, Exodus, etc.)
+ * 
+ * @author cjburrell
+ * 
+ */
+public interface BookSelectedEventHandler extends EventHandler {
+
+	/**
+	 * This method is called when a @see {@link BookSelectedEvent} is triggered
+	 * 
+	 * @param event that is provided to the handler
+	 */
+	void onBookSelected(BookSelectedEvent event);
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/DictionaryDefinitionFoundHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/DictionaryDefinitionFoundHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/DictionaryDefinitionFoundHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,22 @@
+package com.tyndalehouse.step.web.client.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.client.event.DictionaryDefinitionFoundEvent;
+
+/**
+ * This contract is relevant to any handler who wants to be notified when a
+ * definition was looked up from the server
+ * 
+ * @author cjburrell
+ * 
+ */
+public interface DictionaryDefinitionFoundHandler extends EventHandler {
+	/**
+	 * This method is fired when a dictionary definition has been looked up from
+	 * the server
+	 * 
+	 * @param dictionaryDefintionFoundEvent the dictionary definition found
+	 *            event, containing the results from the server
+	 */
+	void onDefinitionFound(DictionaryDefinitionFoundEvent dictionaryDefintionFoundEvent);
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/LemmaClickedEventHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/LemmaClickedEventHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/LemmaClickedEventHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,21 @@
+package com.tyndalehouse.step.web.client.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.client.event.LemmaClickedEvent;
+
+/**
+ * Contract for handlers who are interested in the user clicking on a portion of
+ * scripture which was tagged with a lemma
+ * 
+ * @author cjburrell
+ * 
+ */
+public interface LemmaClickedEventHandler extends EventHandler {
+	/**
+	 * This is fired when a click on a portion of scripture tagged with a lemma
+	 * has occured
+	 * 
+	 * @param lemmaClickedEvent the event that is provided to the handler
+	 */
+	void onLemmaClicked(LemmaClickedEvent lemmaClickedEvent);
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/ModuleChangeEventHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/ModuleChangeEventHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/ModuleChangeEventHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,20 @@
+package com.tyndalehouse.step.web.client.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.client.event.ModuleChangeEvent;
+
+/**
+ * Contract for handlers interested in a selection of a different module
+ * 
+ * @author cjburrell
+ * 
+ */
+public interface ModuleChangeEventHandler extends EventHandler {
+	/**
+	 * Called when the user has selected a different module
+	 * 
+	 * @param event provided to the handler containing the new module
+	 *            combination
+	 */
+	void onModuleChange(ModuleChangeEvent event);
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/ScriptureChangeEventHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/ScriptureChangeEventHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/ScriptureChangeEventHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,20 @@
+package com.tyndalehouse.step.web.client.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.client.event.ScriptureChangeEvent;
+
+/**
+ * Handler contract for when the user changes the portion of scripture he is
+ * viewing
+ * 
+ * @author cjburrell
+ * 
+ */
+public interface ScriptureChangeEventHandler extends EventHandler {
+	/**
+	 * Fired when the user changes the portion of scripture currently viewed
+	 * 
+	 * @param event event containing the details of the new scripture requested
+	 */
+	void onScriptureChange(ScriptureChangeEvent event);
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/TimebandListUpdateRequiredEventHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/TimebandListUpdateRequiredEventHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/TimebandListUpdateRequiredEventHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,22 @@
+package com.tyndalehouse.step.web.client.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.client.event.TimebandListUpdateRequiredEvent;
+
+/**
+ * Contract for handlers requiring notification of updates to the number of
+ * events on the timebands
+ * 
+ * @author cjburrell
+ * 
+ */
+public interface TimebandListUpdateRequiredEventHandler extends EventHandler {
+	/**
+	 * This is fired when new events are added to the timeband, or when events
+	 * are no longer in the visible section
+	 * 
+	 * @param timebandListUpdateRequiredEvent the event containing the new
+	 *            statistics to be displayed
+	 */
+	void onTimebandListRequiringUpdate(TimebandListUpdateRequiredEvent timebandListUpdateRequiredEvent);
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/TimelineScrollEventHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/TimelineScrollEventHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/TimelineScrollEventHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,23 @@
+package com.tyndalehouse.step.web.client.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.client.event.TimelineScrollEvent;
+
+/**
+ * Contract for handlers wanting to be alerted when the timeline is being
+ * scrolled
+ * 
+ * @author cjburrell
+ * 
+ */
+public interface TimelineScrollEventHandler extends EventHandler {
+
+	/**
+	 * Fired when the timeline is being scrolled, before new events are
+	 * requested from the server
+	 * 
+	 * @param event event containing the new portions of time to be requested
+	 *            from the server
+	 */
+	void onScroll(TimelineScrollEvent event);
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/UserInterestInBandEventHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/UserInterestInBandEventHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/UserInterestInBandEventHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,23 @@
+package com.tyndalehouse.step.web.client.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.client.event.UserInterestInBandEvent;
+
+/**
+ * Contract for handlers requiring notifications of timebands being
+ * selected/unselected
+ * 
+ * @author cjburrell
+ * 
+ */
+public interface UserInterestInBandEventHandler extends EventHandler {
+
+	/**
+	 * fired when a timeband has been selected/nselected
+	 * 
+	 * @param userInterestInBandEvent contains information about the timeband
+	 *            that was selected/nselected
+	 */
+	void onUserInterestedInBand(UserInterestInBandEvent userInterestInBandEvent);
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/VersionChangeEventHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/VersionChangeEventHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/eventhandler/VersionChangeEventHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,21 @@
+package com.tyndalehouse.step.web.client.eventhandler;
+
+import com.google.gwt.event.shared.EventHandler;
+import com.tyndalehouse.step.web.client.event.VersionChangeEvent;
+
+/**
+ * Contract for handlers requiring updates when the user changes the version of
+ * the bible he is currently accessing
+ * 
+ * @author cjburrell
+ * 
+ */
+public interface VersionChangeEventHandler extends EventHandler {
+
+	/**
+	 * fired when the user selects a different bible version
+	 * 
+	 * @param event the event containing the new version information
+	 */
+	void onVersionChange(VersionChangeEvent event);
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/gin/StepClientModule.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/gin/StepClientModule.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/gin/StepClientModule.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,74 @@
+package com.tyndalehouse.step.web.client.gin;
+
+import net.customware.gwt.dispatch.client.DefaultDispatchAsync;
+import net.customware.gwt.dispatch.client.DispatchAsync;
+import net.customware.gwt.presenter.client.EventBus;
+import net.customware.gwt.presenter.client.gin.AbstractPresenterModule;
+import net.customware.gwt.presenter.client.place.PlaceManager;
+
+import com.google.inject.Singleton;
+import com.tyndalehouse.step.web.client.common.CachingDispatchAsync;
+import com.tyndalehouse.step.web.client.presenter.AppPresenter;
+import com.tyndalehouse.step.web.client.presenter.HistoryModulePresenter;
+import com.tyndalehouse.step.web.client.presenter.ModuleSelectorPresenter;
+import com.tyndalehouse.step.web.client.presenter.ScripturePresenter;
+import com.tyndalehouse.step.web.client.presenter.ScriptureSelectorPresenter;
+import com.tyndalehouse.step.web.client.presenter.StepPresenter;
+import com.tyndalehouse.step.web.client.presenter.TimebandListPresenter;
+import com.tyndalehouse.step.web.client.presenter.TimelinePresenter;
+import com.tyndalehouse.step.web.client.service.eventbus.StepEventBusImpl;
+import com.tyndalehouse.step.web.client.view.HistoryModuleView;
+import com.tyndalehouse.step.web.client.view.ModuleSelectorView;
+import com.tyndalehouse.step.web.client.view.ScriptureSelectorView;
+import com.tyndalehouse.step.web.client.view.ScriptureView;
+import com.tyndalehouse.step.web.client.view.StepView;
+import com.tyndalehouse.step.web.client.view.TimebandListView;
+import com.tyndalehouse.step.web.client.view.TimelineView;
+
+/**
+ * Gin configuration for the the step client. In addition to normal guice
+ * operations, this binds presenters to their views
+ * 
+ * @author cjburrell
+ * 
+ */
+public class StepClientModule extends AbstractPresenterModule {
+
+	@Override
+	protected void configure() {
+
+		// put the bindings in here
+
+		bind(EventBus.class).to(StepEventBusImpl.class).in(Singleton.class);
+		bind(TimebandListPresenter.Display.class).to(TimebandListView.class);
+
+		bind(AppPresenter.class).in(Singleton.class);
+		bind(PlaceManager.class).in(Singleton.class);
+
+		bindPresenter(StepPresenter.class, StepPresenter.Display.class, StepView.class);
+		bind(ScriptureSelectorPresenter.class);
+		bind(ScriptureSelectorPresenter.Display.class).to(ScriptureSelectorView.class).in(
+			Singleton.class);
+		bind(ModuleSelectorPresenter.class);
+		bind(ModuleSelectorPresenter.Display.class).to(ModuleSelectorView.class)
+			.in(Singleton.class);
+		bind(ScripturePresenter.class);
+		bind(ScripturePresenter.Display.class).to(ScriptureView.class); // .in(Singleton.class);
+		bind(TimelinePresenter.class);
+		bind(TimelinePresenter.Display.class).to(TimelineView.class); // .in(Singleton.class);
+		
+		//		
+		// bind(ITimeLineRender.class).to(TimelineRenderer.class);
+
+		bind(HistoryModulePresenter.class);
+		bind(HistoryModulePresenter.Display.class).to(HistoryModuleView.class);
+
+		// bind(new TypeLiteral<StepModulePresenter<? extends
+		// StepModulePresenter.Display>>() {
+		// }).to(HistoryModulePresenter.class);
+
+		bind(DispatchAsync.class).to(DefaultDispatchAsync.class).in(Singleton.class);
+		bind(CachingDispatchAsync.class);
+
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/gin/StepInjector.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/gin/StepInjector.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/gin/StepInjector.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,30 @@
+package com.tyndalehouse.step.web.client.gin;
+
+import net.customware.gwt.presenter.client.place.PlaceManager;
+
+import com.google.gwt.inject.client.GinModules;
+import com.google.gwt.inject.client.Ginjector;
+import com.tyndalehouse.step.web.client.presenter.AppPresenter;
+
+/**
+ * Gin injector. This defines the modules all the Gin modules
+ * 
+ * @author cjburrell
+ * 
+ */
+ at GinModules( StepClientModule.class )
+public interface StepInjector extends Ginjector {
+	/**
+	 * Returns the App Presenter, the main presenter for STEP
+	 * 
+	 * @return the main presenter for STEP
+	 */
+	AppPresenter getAppPresenter();
+
+	/**
+	 * Returns a place manager
+	 * 
+	 * @return the step place manager
+	 */
+	PlaceManager getPlaceManager();
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/AppPresenter.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/AppPresenter.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/AppPresenter.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,67 @@
+package com.tyndalehouse.step.web.client.presenter;
+
+import net.customware.gwt.dispatch.client.DispatchAsync;
+
+import com.allen_sauer.gwt.log.client.Log;
+import com.google.gwt.user.client.ui.HasWidgets;
+import com.google.inject.Inject;
+
+/**
+ * Main presenter for STEP, entry point
+ * 
+ * @author cjburrell
+ * 
+ */
+public class AppPresenter {
+	/**
+	 * container for any main widgets
+	 */
+	private HasWidgets container;
+
+	// TODO: investigate whether there is a neater way of doing this
+	/**
+	 * Main dispatcher.
+	 */
+	@SuppressWarnings(value = "unused")
+	private final DispatchAsync dispatcher;
+
+	/**
+	 * The step presenter - TODO: probably one layer of abstration too many,
+	 * should be moved this class into StepPresenter
+	 */
+	private final StepPresenter stepPresenter;
+
+	/**
+	 * The default app presenter for STEP.
+	 * 
+	 * @param dispatcher the dispatcher to use within this class (passed in here
+	 *            to get it initialised)
+	 * @param stepPresenter the step presenter responsible for handling all
+	 *            other presenters and views
+	 */
+	// passing them in to have GIN initialise them!
+	@Inject
+	public AppPresenter(final DispatchAsync dispatcher, final StepPresenter stepPresenter) {
+		this.dispatcher = dispatcher;
+		this.stepPresenter = stepPresenter;
+		Log.debug("AppPresenter is being initialised");
+	}
+
+	/**
+	 * Call go to initialise the step application and render
+	 * 
+	 * @param container container on which to add the Step Application
+	 */
+	public void go(final HasWidgets container) {
+		this.container = container;
+		showMain();
+	}
+
+	/**
+	 * Repaints the page with the step presenter/view
+	 */
+	private void showMain() {
+		container.clear();
+		container.add(stepPresenter.getDisplay().asWidget());
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/HistoryModulePresenter.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/HistoryModulePresenter.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/HistoryModulePresenter.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,102 @@
+package com.tyndalehouse.step.web.client.presenter;
+
+import net.customware.gwt.presenter.client.EventBus;
+import net.customware.gwt.presenter.client.place.Place;
+import net.customware.gwt.presenter.client.place.PlaceRequest;
+import net.customware.gwt.presenter.client.widget.WidgetDisplay;
+import net.customware.gwt.presenter.client.widget.WidgetPresenter;
+
+import com.google.inject.Inject;
+
+/**
+ * History module presenter, responsible for displaying articles on the page
+ * 
+ * @author cjburrell
+ * 
+ */
+public class HistoryModulePresenter extends WidgetPresenter<HistoryModulePresenter.Display> {
+
+	/**
+	 * Interface for the History Module View
+	 * 
+	 * @author cjburrell
+	 * 
+	 */
+	public interface Display extends WidgetDisplay {
+
+	}
+
+	/**
+	 * default constructor, injected by Gin
+	 * 
+	 * @param display display, comes from Gin
+	 * @param eventBus eventBus comes from Gin
+	 */
+	@Inject
+	public HistoryModulePresenter(final Display display, final EventBus eventBus) {
+		super(display, eventBus);
+		bind();
+	}
+
+	@Override
+	public Place getPlace() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public void refreshDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void revealDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	protected void onBind() {
+
+		// eventBus.addHandler(MultipleWordsSelectedEvent.TYPE, new
+		// MultipleWordsSelectedEventHandler() {
+		//
+		// @Override
+		// public void onMultipleWordsSelected(MultipleWordsSelectedEvent event)
+		// {
+		// // TODO Auto-generated method stub
+		//				
+		// }
+		// });
+		//
+		// eventBus.addHandler(WordSelectedEvent.TYPE, new
+		// WordSelectedEventHandler() {
+		//
+		// @Override
+		// public void onWordSelectedEvent(WordSelectedEvent event) {
+		//				
+		// }
+		// });
+		//
+		// eventBus.addHandler(DepthChangeEvent.TYPE, new
+		// DepthChangeEventHandler() {
+		//
+		// @Override
+		// public void onDepthChange(DepthChangeEvent event) {
+		//				
+		// }
+		// });
+	}
+
+	@Override
+	protected void onPlaceRequest(final PlaceRequest request) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	protected void onUnbind() {
+		// TODO Auto-generated method stub
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ModuleSelectorPresenter.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ModuleSelectorPresenter.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ModuleSelectorPresenter.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,205 @@
+package com.tyndalehouse.step.web.client.presenter;
+
+import java.util.List;
+
+import net.customware.gwt.dispatch.client.DispatchAsync;
+import net.customware.gwt.presenter.client.EventBus;
+import net.customware.gwt.presenter.client.place.Place;
+import net.customware.gwt.presenter.client.place.PlaceRequest;
+import net.customware.gwt.presenter.client.widget.WidgetDisplay;
+import net.customware.gwt.presenter.client.widget.WidgetPresenter;
+
+import com.google.gwt.event.dom.client.ChangeEvent;
+import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.event.dom.client.HasChangeHandlers;
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.client.event.ModuleChangeEvent;
+import com.tyndalehouse.step.web.client.service.refdata.ModuleRefData;
+import com.tyndalehouse.step.web.client.toolkit.HasSource;
+
+/**
+ * Module selector module, responsible for displaying the dropdowns on the user
+ * interface
+ * 
+ * @author cjburrell
+ * 
+ */
+public class ModuleSelectorPresenter extends WidgetPresenter<ModuleSelectorPresenter.Display> implements
+		ChangeHandler {
+
+	/**
+	 * Interface to the module selector view
+	 * 
+	 * @author cjburrell
+	 * 
+	 */
+	public interface Display extends WidgetDisplay {
+		/**
+		 * 
+		 * @return Returns any change handlers so that the presenter can
+		 *         register event handlers
+		 */
+		HasChangeHandlers getModuleChangeHandlers();
+
+		/**
+		 * 
+		 * @return returns a change handler for the "Depth" dropdown/list
+		 */
+		HasChangeHandlers getModuleDepthChangeHandlers();
+
+		/**
+		 * @return returns the source associated to the Module Depth
+		 *         dropdown/list
+		 */
+		HasSource<List<String>> getModuleDepthSource();
+
+		/**
+		 * 
+		 * @return the source for the module list/dropdown
+		 */
+		HasSource<List<String>> getModuleSource();
+
+		/**
+		 * 
+		 * @return current selected depth (for example scholarly detail)
+		 */
+		String getSelectedDepth();
+
+		/**
+		 * 
+		 * @return currently selected module
+		 */
+		String getSelectedModule();
+
+		/**
+		 * 
+		 * @return currently selected sub-module
+		 */
+		String getSelectedSubModule();
+
+		/**
+		 * 
+		 * @return change handlers on which to register event handlers for the
+		 *         sub module dropdown/list
+		 */
+		HasChangeHandlers getSubModuleChangeHandlers();
+
+		/**
+		 * 
+		 * @return source for the sub module dropdown/list
+		 */
+		HasSource<List<String>> getSubModuleSource();
+
+		/**
+		 * Changes the selected module
+		 * 
+		 * @param newlySelectedModule the new module to be selected
+		 */
+		void setSelectedModule(String newlySelectedModule);
+	}
+
+	/**
+	 * Default constructor
+	 * 
+	 * @param display display passed in by Gin
+	 * @param eventBus eventBus passed in by Gin
+	 * @param dispatcher dispatch passed in by Gin
+	 */
+	@Inject
+	public ModuleSelectorPresenter(final Display display, final EventBus eventBus,
+			final DispatchAsync dispatcher) {
+		super(display, eventBus);
+		bind();
+	}
+
+	@Override
+	public Place getPlace() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	/**
+	 * Used for submodule and depth
+	 * 
+	 * @param event event that was fired by the view.
+	 */
+	public void onChange(final ChangeEvent event) {
+		fireChange();
+	}
+
+	public void refreshDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void revealDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	/**
+	 * adds the module change handlers, for module list, sub module list and
+	 * depth list
+	 */
+	private void addDropdownChangeHandlers() {
+		// fires the dropdown change event as a ModuleChangeEvent
+		display.getModuleChangeHandlers().addChangeHandler(new ChangeHandler() {
+
+			public void onChange(final ChangeEvent event) {
+				// in here, we need to reload the events
+				display.getSubModuleSource().setSource(
+						ModuleRefData.getInstance().getListOfModules(display.getSelectedModule()));
+				// this hopefully fires the on Change below since the sub module
+				// dropdown changes...
+				// but it doesn't :( so...
+				fireChange();
+			}
+		});
+
+		display.getSubModuleChangeHandlers().addChangeHandler(this);
+		display.getModuleDepthChangeHandlers().addChangeHandler(this);
+	}
+
+	/**
+	 * fires the change of dropdown selectors to the event bus.
+	 */
+	private void fireChange() {
+		eventBus.fireEvent(new ModuleChangeEvent(display.getSelectedModule(), display.getSelectedSubModule(),
+				display.getSelectedDepth()));
+
+	}
+
+	@Override
+	protected void onBind() {
+		// do nothing at the moment
+		// add event notifications...
+		addDropdownChangeHandlers();
+
+		// TODO: remove default into configurable options, preferences, etc.
+		final String defaultModule = "History";
+		final ModuleRefData mrd = ModuleRefData.getInstance();
+		final List<String> moduleNames = mrd.getListOfModules("Module");
+		final List<String> subModules = mrd.getListOfModules(defaultModule);
+		final List<String> depths = mrd.getDepths();
+
+		display.setSelectedModule(defaultModule);
+		display.getModuleSource().setSource(moduleNames);
+		display.getSubModuleSource().setSource(subModules);
+		display.getModuleDepthSource().setSource(depths);
+
+		// do i need to fire an module change event?
+	}
+
+	@Override
+	protected void onPlaceRequest(final PlaceRequest request) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	protected void onUnbind() {
+		// TODO Auto-generated method stub
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ScripturePresenter.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ScripturePresenter.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ScripturePresenter.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,230 @@
+package com.tyndalehouse.step.web.client.presenter;
+
+import java.util.List;
+import java.util.SortedMap;
+
+import net.customware.gwt.dispatch.client.DispatchAsync;
+import net.customware.gwt.presenter.client.DisplayCallback;
+import net.customware.gwt.presenter.client.EventBus;
+import net.customware.gwt.presenter.client.place.Place;
+import net.customware.gwt.presenter.client.place.PlaceRequest;
+import net.customware.gwt.presenter.client.widget.WidgetDisplay;
+import net.customware.gwt.presenter.client.widget.WidgetPresenter;
+
+import com.allen_sauer.gwt.log.client.Log;
+import com.google.gwt.event.dom.client.ChangeEvent;
+import com.google.gwt.event.dom.client.ChangeHandler;
+import com.google.gwt.event.dom.client.HasChangeHandlers;
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.client.event.LemmaClickedEvent;
+import com.tyndalehouse.step.web.client.event.ScriptureChangeEvent;
+import com.tyndalehouse.step.web.client.event.VersionChangeEvent;
+import com.tyndalehouse.step.web.client.eventhandler.LemmaClickedEventHandler;
+import com.tyndalehouse.step.web.client.eventhandler.ScriptureChangeEventHandler;
+import com.tyndalehouse.step.web.client.toolkit.HasSource;
+import com.tyndalehouse.step.web.shared.command.GetAvailableBibleVersionsCommand;
+import com.tyndalehouse.step.web.shared.command.GetCurrentBibleTextCommand;
+import com.tyndalehouse.step.web.shared.common.scripturelookup.BibleTextLookupType;
+import com.tyndalehouse.step.web.shared.result.GetAvailableBibleVersionsResult;
+import com.tyndalehouse.step.web.shared.result.GetCurrentBibleTextResult;
+import com.tyndalehouse.step.web.shared.scripture.Passage;
+
+/**
+ * This presenter is responsible for displaying scripture to the user, in an
+ * interactive way including the highlight-on-click, querying the server for
+ * portions of text, etc.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class ScripturePresenter extends WidgetPresenter<ScripturePresenter.Display> {
+
+	/**
+	 * Description of the view for presenting scripture to the user
+	 * 
+	 * @author cjburrell
+	 * 
+	 */
+	public interface Display extends WidgetDisplay {
+		/**
+		 * TODO: change the name, it's a bit meaningless change handlers to the
+		 * bible versions dropdown
+		 * 
+		 * @return bible versions change handlers
+		 */
+		HasChangeHandlers getChangeHandlers();
+
+		/**
+		 * 
+		 * @return the currently selected bible version on the UI
+		 */
+		String getSelectedBibleVersion();
+
+		/**
+		 * 
+		 * @return a map (intials -> bible Name) used as the source of the bible
+		 *         versions dropdown
+		 */
+		HasSource<SortedMap<String, String>> getSource();
+
+		/**
+		 * action to highlight portions of the biblical text that are tagged
+		 * with a lemma
+		 * 
+		 * @param lemmas lemmas to look for in the presented biblical text.
+		 */
+		void highlight(List<String> lemmas);
+
+		/**
+		 * @param passage a logical passage to be displayed
+		 */
+		void setPassage(Passage passage);
+
+		/**
+		 * @param text the text form of the passage
+		 */
+		void setPassage(String text);
+	}
+
+	/**
+	 * default asynchronous dispatcher
+	 */
+	private final DispatchAsync dispatcher;
+
+	/**
+	 * the view itself, used to interact with it
+	 */
+	private final ScriptureSelectorPresenter.Display scriptureSelectorView;
+
+	/**
+	 * 
+	 * @param display the view, provided by Gin
+	 * @param eventBus the event bus, provided by Gin
+	 * @param dispatcher the dispatcher, provided by Gin
+	 * @param scriptureSelectorView the scripture selector view (i.e. the bit
+	 *            with the reference in it), provided by Gin
+	 */
+	@Inject
+	public ScripturePresenter(final Display display, final EventBus eventBus,
+		final DispatchAsync dispatcher,
+		final ScriptureSelectorPresenter.Display scriptureSelectorView) {
+		super(display, eventBus);
+		// TODO: remove dependency on scripture selector view
+		this.dispatcher = dispatcher;
+		this.scriptureSelectorView = scriptureSelectorView;
+		Log.debug("Initialising Scripture Presenter");
+		bind();
+	}
+
+	@Override
+	public Place getPlace() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public void refreshDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void revealDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	/**
+	 * Sends a request to the server to get the new text to be displayed. TODO:
+	 * this should be parameterized since the cmd options are set to defaults
+	 * here for testing
+	 */
+	private void doRefreshScripture() {
+		final GetCurrentBibleTextCommand cmd = new GetCurrentBibleTextCommand(display
+			.getSelectedBibleVersion(), scriptureSelectorView.getReference().getValue());
+		// TODO: decide if this should be made static or UI driven
+		cmd.setTypeOfLookup(BibleTextLookupType.REVERSE_INTERLINEAR);
+
+		dispatcher.execute(cmd, new DisplayCallback<GetCurrentBibleTextResult>(display) {
+
+			@Override
+			protected void handleFailure(final Throwable e) {
+				Log.error("An error has occurred", e);
+			}
+
+			@Override
+			protected void handleSuccess(final GetCurrentBibleTextResult result) {
+				// String text = result.getPassageText();
+				display.setPassage(result.getPassage());
+			}
+
+		});
+	}
+
+	@Override
+	protected void onBind() {
+		Log.debug("Binding Scripture Presenter");
+		// get list of versions now...
+		dispatcher.execute(new GetAvailableBibleVersionsCommand(),
+			new DisplayCallback<GetAvailableBibleVersionsResult>(display) {
+				@Override
+				protected void handleFailure(final Throwable e) {
+					Log.error("An error occurred while retrieving bible versions: ", e);
+				}
+
+				@Override
+				protected void handleSuccess(final GetAvailableBibleVersionsResult result) {
+					display.getSource().setSource(result.getBooks());
+				}
+			});
+
+		display.getChangeHandlers().addChangeHandler(new ChangeHandler() {
+			public void onChange(final ChangeEvent event) {
+				eventBus.fireEvent(new VersionChangeEvent());
+				doRefreshScripture();
+			}
+		});
+
+		eventBus.addHandler(ScriptureChangeEvent.TYPE, new ScriptureChangeEventHandler() {
+
+			public void onScriptureChange(final ScriptureChangeEvent event) {
+				Log.debug("Scripture Change event captured");
+				doRefreshScripture();
+			}
+		});
+
+		// TODO: this handler needs to be moved somewhere else, and fire off
+		// definition found
+		// TODO: given the handler name, our event bus, should be able to derive
+		// the type of it,
+		// since the type = Type<HandlerName>, at which point we can probably
+		// get rid of
+		// the type variable in the event.
+		// we would have to change the event to return the static type declared
+		// in the
+		// event handler
+
+		final LemmaClickedEventHandler lceh = new LemmaClickedEventHandler() {
+			public void onLemmaClicked(final LemmaClickedEvent lemmaClickedEvent) {
+				Log.error("Lemma Clicked event handler invoked");
+				highlightAllLemmas(lemmaClickedEvent.getLemma());
+			}
+
+			private void highlightAllLemmas(final List<String> lemmas) {
+				display.highlight(lemmas);
+			}
+		};
+		eventBus.addHandler(LemmaClickedEvent.TYPE, lceh);
+	}
+
+	@Override
+	protected void onPlaceRequest(final PlaceRequest request) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	protected void onUnbind() {
+		// TODO Auto-generated method stub
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ScriptureSelectorPresenter.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ScriptureSelectorPresenter.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/ScriptureSelectorPresenter.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,160 @@
+package com.tyndalehouse.step.web.client.presenter;
+
+import java.util.Collection;
+
+import net.customware.gwt.dispatch.client.DispatchAsync;
+import net.customware.gwt.presenter.client.DisplayCallback;
+import net.customware.gwt.presenter.client.EventBus;
+import net.customware.gwt.presenter.client.place.Place;
+import net.customware.gwt.presenter.client.place.PlaceRequest;
+import net.customware.gwt.presenter.client.widget.WidgetDisplay;
+import net.customware.gwt.presenter.client.widget.WidgetPresenter;
+
+import com.allen_sauer.gwt.log.client.Log;
+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.gwt.user.client.ui.HasValue;
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.client.event.ScriptureChangeEvent;
+import com.tyndalehouse.step.web.shared.command.GetBibleBooksCommand;
+import com.tyndalehouse.step.web.shared.result.GetBibleBooksCommandResult;
+
+/**
+ * Presenter for the Scripture Selector Presenter module. This module aims to
+ * present the user with a way of selecting a passage, including suggesting the
+ * bible book.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class ScriptureSelectorPresenter extends WidgetPresenter<ScriptureSelectorPresenter.Display> {
+	/**
+	 * The contract with the view, which will disaply a way for the user to
+	 * select/key in a bible reference
+	 * 
+	 * @author cjburrell
+	 * 
+	 */
+	public interface Display extends WidgetDisplay {
+		/**
+		 * adds a suggestion to the list of bibles
+		 * 
+		 * @param suggestion a suggestion, such as a bible book name
+		 */
+		void addSuggestion(String suggestion);
+
+		/**
+		 * Adds a list of suggestions
+		 * 
+		 * @param suggestions the collection of suggestions (bible book names,
+		 *            for e.g.)
+		 */
+		void addSuggestions(Collection<String> suggestions);
+
+		/**
+		 * @return the reference which is currently keyed in
+		 */
+		HasValue<String> getReference();
+
+		/**
+		 * @return the handler for clicking on a search button
+		 */
+		HasClickHandlers getSearch();
+
+	}
+
+	/**
+	 * The default dispatcher to use to send requests to the server
+	 */
+	private final DispatchAsync dispatcher;
+
+	/**
+	 * Constructor to set up the timeline module
+	 * 
+	 * @param display the view, passed in by Gin
+	 * @param eventBus the event bus, passed in by Gin
+	 * @param dispatcher the dispatcher, passed in by Gin
+	 */
+	@Inject
+	public ScriptureSelectorPresenter(final Display display, final EventBus eventBus,
+			final DispatchAsync dispatcher) {
+		super(display, eventBus);
+
+		this.dispatcher = dispatcher;
+
+		Log.debug("ScriptureSelectorPresenter initialised");
+		bind();
+	}
+
+	/**
+	 * @return the current reference as keyed in by the user.
+	 */
+	public String getCurrentReference() {
+		return display.getReference().getValue();
+	}
+
+	@Override
+	public Place getPlace() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public void refreshDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void revealDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	protected void onBind() {
+		Log.debug("onBind called in ScriptureSelector");
+
+		dispatcher.execute(new GetBibleBooksCommand(), new DisplayCallback<GetBibleBooksCommandResult>(
+				display) {
+			@Override
+			protected void handleFailure(final Throwable e) {
+				// TODO Auto-generated method stub
+				Log.error("Unable to get books from server", e);
+			}
+
+			@Override
+			protected void handleSuccess(final GetBibleBooksCommandResult value) {
+				display.addSuggestions(value.getBooks());
+			}
+		});
+
+		display.getSearch().addClickHandler(new ClickHandler() {
+
+			public void onClick(final ClickEvent event) {
+				// can't use complicated classes here, as GWT java doesn't cope!
+				final String reference = display.getReference().getValue();
+				if (reference == null || reference.length() == 0) {
+					// return validation message perhaps? or ignore?
+					Log.error("No reference was provided, so no lookup can occur.");
+					return;
+				}
+
+				eventBus.fireEvent(new ScriptureChangeEvent(display.getReference().getValue()));
+			}
+		});
+
+	}
+
+	@Override
+	protected void onPlaceRequest(final PlaceRequest request) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	protected void onUnbind() {
+		// TODO Auto-generated method stub
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/StepPresenter.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/StepPresenter.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/StepPresenter.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,139 @@
+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;
+import net.customware.gwt.presenter.client.place.Place;
+import net.customware.gwt.presenter.client.place.PlaceRequest;
+import net.customware.gwt.presenter.client.widget.WidgetDisplay;
+import net.customware.gwt.presenter.client.widget.WidgetPresenter;
+
+import com.allen_sauer.gwt.log.client.Log;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.PopupPanel;
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.client.event.LemmaClickedEvent;
+import com.tyndalehouse.step.web.client.eventhandler.LemmaClickedEventHandler;
+import com.tyndalehouse.step.web.shared.command.GetDictionaryDefinitionCommand;
+import com.tyndalehouse.step.web.shared.result.GetDictionaryDefinitionResult;
+
+/**
+ * This is the main Presenter, when the view is created, all other presenters
+ * are created as a result.
+ * 
+ * It acts as a singleton for each browser
+ * 
+ * @author cjburrell
+ * 
+ */
+public class StepPresenter extends WidgetPresenter<StepPresenter.Display> {
+	/**
+	 * The contract with the Step View, the main layout of Step
+	 * 
+	 * @author cjburrell
+	 * 
+	 */
+	public interface Display extends WidgetDisplay {
+	}
+
+	/**
+	 * the default dispatcher for async server requests
+	 */
+	private final DispatchAsync dispatcher;
+
+	/**
+	 * Constructor to set up the timeline module
+	 * 
+	 * @param display the view, passed in by Gin
+	 * @param eventBus the event bus, passed in by Gin
+	 * @param dispatcher the dispatcher, passed in by Gin
+	 */
+	@Inject
+	public StepPresenter(final Display display, final EventBus eventBus, final DispatchAsync dispatcher) {
+		super(display, eventBus);
+		this.dispatcher = dispatcher;
+
+		Log.debug("StepPresenter initialised");
+		bind();
+	}
+
+	@Override
+	public Place getPlace() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public void refreshDisplay() {
+		// TODO Auto-generated method stub
+	}
+
+	public void revealDisplay() {
+		// TODO Auto-generated method stub
+	}
+
+	/**
+	 * adds event handlers when they need to be parsed only once, but multiple
+	 * presenters may be interested this is a proxy. Typically an event should
+	 * then be fired if necessary to the presenters
+	 */
+	private void addSingletonEventHandlers() {
+		// TODO: this handler needs to be moved somewhere else, and fire off
+		// definition found
+		eventBus.addHandler(LemmaClickedEvent.TYPE, new LemmaClickedEventHandler() {
+
+			public void onLemmaClicked(final LemmaClickedEvent lemmaClickedEvent) {
+				Log.error("Lemma Clicked event handler invoked");
+				getLemmaDefinition(lemmaClickedEvent.getLemma());
+			}
+
+			private void getLemmaDefinition(final List<String> lemmaDefs) {
+				final GetDictionaryDefinitionCommand cmd = new GetDictionaryDefinitionCommand();
+				cmd.setLookupReference(lemmaDefs);
+
+				dispatcher.execute(cmd, new DisplayCallback<GetDictionaryDefinitionResult>(display) {
+					@Override
+					protected void handleFailure(final Throwable e) {
+						Log.error(e.getMessage());
+					}
+
+					@Override
+					protected void handleSuccess(final GetDictionaryDefinitionResult lemmaDefinition) {
+						Log.warn(lemmaDefinition.getXsltedDefinition());
+
+						// TODO: check whether definition came back alright!
+						// TODO: change the XSLT to something nicer
+						final PopupPanel popup = new PopupPanel();
+						popup.setWidget(new HTML(lemmaDefinition.getXsltedDefinition()));
+						popup.setAutoHideEnabled(true);
+						popup.show();
+
+						// scripture view doesn't need to know about this...
+						// TODO: remove DictionaryDefinitionFoundEvent and
+						// Handler
+						// eventBus.fireEvent(new
+						// DictionaryDefinitionFoundEvent(lemmaDefinition.getXsltedDefinition()));
+					}
+				});
+			}
+		});
+
+	}
+
+	@Override
+	protected void onBind() {
+		Log.debug("onBind called in STEP presenter");
+		addSingletonEventHandlers();
+	}
+
+	@Override
+	protected void onPlaceRequest(final PlaceRequest request) {
+		// TODO Auto-generated method stub
+	}
+
+	@Override
+	protected void onUnbind() {
+		// TODO Auto-generated method stub
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/TimebandListPresenter.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/TimebandListPresenter.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/TimebandListPresenter.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,98 @@
+package com.tyndalehouse.step.web.client.presenter;
+
+import java.util.List;
+
+import net.customware.gwt.presenter.client.EventBus;
+import net.customware.gwt.presenter.client.place.Place;
+import net.customware.gwt.presenter.client.place.PlaceRequest;
+import net.customware.gwt.presenter.client.widget.WidgetDisplay;
+import net.customware.gwt.presenter.client.widget.WidgetPresenter;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.client.event.TimebandListUpdateRequiredEvent;
+import com.tyndalehouse.step.web.client.eventhandler.TimebandListUpdateRequiredEventHandler;
+import com.tyndalehouse.step.web.client.toolkit.timeline.helpers.CurrentBandStats;
+
+/**
+ * The TimebandList presenter is the presenter for the Timeband list module.
+ * This module is a list of items, each one representing one timeband. Each item
+ * contains the real-time statistics of what is displayed on the timeband,
+ * including the number of event and the number of events currently visible
+ * 
+ * @author cjburrell
+ * 
+ */
+// TODO: refactor to ensure events get captured and dealt with in the presenter,
+// rather than in the view.
+
+public class TimebandListPresenter extends WidgetPresenter<TimebandListPresenter.Display> {
+
+	/**
+	 * Contract with any TimebandList view
+	 * 
+	 * @author cjburrell
+	 * 
+	 */
+	public interface Display extends WidgetDisplay {
+		/**
+		 * This method updates the list displayed with the latest statistics
+		 * 
+		 * @param stats statistics to be sent to the view for update
+		 */
+		void updateList(List<CurrentBandStats> stats);
+	}
+
+	/**
+	 * Default constructor, injected with Gin
+	 * 
+	 * @param display the view, provided by Gin
+	 * @param eventBus the event bus, provided by Gin
+	 */
+	@Inject
+	public TimebandListPresenter(final TimebandListPresenter.Display display, final EventBus eventBus) {
+		super(display, eventBus);
+		bind();
+	}
+
+	@Override
+	protected void onBind() {
+		eventBus.addHandler(TimebandListUpdateRequiredEvent.TYPE,
+				new TimebandListUpdateRequiredEventHandler() {
+
+					public void onTimebandListRequiringUpdate(
+							final TimebandListUpdateRequiredEvent timebandListUpdateRequiredEvent) {
+						final List<CurrentBandStats> stats = timebandListUpdateRequiredEvent
+								.getTimelineStats();
+						display.updateList(stats);
+					}
+				});
+	}
+
+	@Override
+	public Place getPlace() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+	
+	public void refreshDisplay() {
+		// TODO Auto-generated method stub
+		
+	}
+	
+	public void revealDisplay() {
+		// TODO Auto-generated method stub
+		
+	}
+
+	@Override
+	protected void onPlaceRequest(final PlaceRequest request) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	protected void onUnbind() {
+		// TODO Auto-generated method stub
+
+	}
+}

Added: 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	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/presenter/TimelinePresenter.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,301 @@
+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;
+import net.customware.gwt.presenter.client.place.Place;
+import net.customware.gwt.presenter.client.place.PlaceRequest;
+import net.customware.gwt.presenter.client.widget.WidgetDisplay;
+import net.customware.gwt.presenter.client.widget.WidgetPresenter;
+
+import com.allen_sauer.gwt.log.client.Log;
+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.event.ScriptureChangeEvent;
+import com.tyndalehouse.step.web.client.event.TimebandListUpdateRequiredEvent;
+import com.tyndalehouse.step.web.client.event.TimelineScrollEvent;
+import com.tyndalehouse.step.web.client.eventhandler.ScriptureChangeEventHandler;
+import com.tyndalehouse.step.web.client.eventhandler.TimelineScrollEventHandler;
+import com.tyndalehouse.step.web.client.toolkit.timeline.TimeEvent;
+import com.tyndalehouse.step.web.client.toolkit.timeline.Timeband;
+import com.tyndalehouse.step.web.client.toolkit.timeline.Timeline;
+import com.tyndalehouse.step.web.client.toolkit.timeline.components.TimelineConstants;
+import com.tyndalehouse.step.web.client.toolkit.timeline.exceptions.TimeBandNotFoundException;
+import com.tyndalehouse.step.web.shared.command.GetEventsForDateRangeCommand;
+import com.tyndalehouse.step.web.shared.command.GetTimelineOriginForScriptureCommand;
+import com.tyndalehouse.step.web.shared.command.GetTimelineUISetupCommand;
+import com.tyndalehouse.step.web.shared.common.timeline.TimeBandVisibleDate;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineBean;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineEventBean;
+import com.tyndalehouse.step.web.shared.result.GetEventsForDateRangeResult;
+import com.tyndalehouse.step.web.shared.result.GetTimelineOriginForScriptureResult;
+import com.tyndalehouse.step.web.shared.result.GetTimelineUISetupResult;
+import com.tyndalehouse.step.web.shared.timeline.Unit;
+
+/**
+ * TimelinePresenter is the presenter object for the Timeline module This is
+ * responsible for getting all the events from the server, firing changes across
+ * the event bus, if need be, repainting the timeline module, etc.
+ * 
+ * @author cjburrell
+ * 
+ */
+// TODO: timeline module needs refactoring quite a bit, since most of the logic
+// seems to be doing the view
+// as well, really ought to rewrite parts of it to remove the logic from the
+// display component
+public class TimelinePresenter extends WidgetPresenter<TimelinePresenter.Display> {
+	/**
+	 * the view contract for the timeline module
+	 * 
+	 * @author cjburrell
+	 * 
+	 */
+	public interface Display extends WidgetDisplay {
+
+		/**
+		 * @return the timeline module
+		 */
+		Timeline getTimeline();
+
+		/**
+		 * @return the zoom in Button
+		 */
+		HasClickHandlers getZoomIn();
+
+		/**
+		 * @return The zoom out button
+		 */
+		HasClickHandlers getZoomOut();
+	}
+
+	/**
+	 * The dispatcher for requests to the server
+	 */
+	private final DispatchAsync dispatcher;
+
+	/**
+	 * Constructor to set up the timeline module
+	 * 
+	 * @param display the view, passed in by Gin
+	 * @param eventBus the event bus, passed in by Gin
+	 * @param dispatcher the dispatcher, passed in by Gin
+	 */
+	@Inject
+	public TimelinePresenter(final Display display, final EventBus eventBus, final DispatchAsync dispatcher) {
+		super(display, eventBus);
+		this.dispatcher = dispatcher;
+
+		bind();
+	}
+
+	@Override
+	public Place getPlace() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	public void refreshDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void revealDisplay() {
+		// TODO Auto-generated method stub
+
+	}
+
+	/**
+	 * registers interest in @see {@link ScriptureChangeEvent}
+	 */
+	private void addScriptureChangeHandler() {
+		eventBus.addHandler(ScriptureChangeEvent.TYPE, new ScriptureChangeEventHandler() {
+
+			public void onScriptureChange(final ScriptureChangeEvent event) {
+				Log.debug("Scripture Change event captured");
+
+				dispatcher.execute(new GetTimelineOriginForScriptureCommand(event.getNewReference()),
+						new DisplayCallback<GetTimelineOriginForScriptureResult>(display) {
+
+							@Override
+							protected void handleFailure(final Throwable e) {
+								Log.error("Failed to get timeline origin", e);
+							}
+
+							@Override
+							protected void handleSuccess(final GetTimelineOriginForScriptureResult value) {
+								if (!value.isEmpty()) {
+									final Timeline tl = display.getTimeline();
+									tl.repaint(value.getOriginDate(), value.getSuggestedTimeScale(), value
+											.getTimebandId());
+									// don't fire event to update list here,
+									// events haven't been requested yet!
+								}
+								// validation will be coped for elsewhere, in
+								// the relevant module, therefore do nothing at
+								// this stage
+							}
+
+						});
+
+				// so now we update the timeline, and we need to work out
+				// where to go.
+
+			}
+		});
+	}
+
+	/**
+	 * 
+	 */
+	private void addScrollHandler() {
+		eventBus.addHandler(TimelineScrollEvent.TYPE, new TimelineScrollEventHandler() {
+			public void onScroll(final TimelineScrollEvent event) {
+				dispatcher.execute(new GetEventsForDateRangeCommand(event.getTimebandVisibleDates()),
+						new DisplayCallback<GetEventsForDateRangeResult>(display) {
+							@Override
+							protected void handleFailure(final Throwable e) {
+								Log.error("An error occurred while tyring to get events for the timeline", e);
+							}
+
+							// TODO: push this down in to timeline component?
+							@Override
+							protected void handleSuccess(final GetEventsForDateRangeResult resultingEvents) {
+								Log.debug("Request for events came back succesfully!");
+								Log.debug("Request was for " + event.getTimebandVisibleDates().size()
+										+ " timebands.");
+
+								final List<TimelineEventBean> events = resultingEvents.getEvents();
+								final Timeline tl = getDisplay().getTimeline();
+
+								for (final TimelineEventBean ev : events) {
+									final int timebandId = ev.getTimelineId();
+
+									try {
+										final Timeband correctBand = tl.getBand(timebandId);
+										correctBand.addEvent(new TimeEvent(ev.getEventId(), ev.getName(), ev
+												.getFromDate(), ev.getToDate(), correctBand));
+									} catch (final 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
+								// and also resize the bands too
+								for (final TimeBandVisibleDate tbvd : event.getTimebandVisibleDates()) {
+									try {
+										final Timeband tb = tl.getBand(tbvd.getTimebandId());
+										tb.adjustRequestedView(tbvd.getMinDate(), tbvd.getMaxDate());
+										tb.resizeBand();
+									} catch (final TimeBandNotFoundException e) {
+										// if for some reason the timeband has
+										// gone, we can but ignore
+										// the error
+										Log.error("Timeband " + tbvd.getTimebandId() + " cannot be found.");
+									}
+								}
+
+								eventBus.fireEvent(new TimebandListUpdateRequiredEvent(tl
+										.getCurrentBandStats()));
+							}
+						});
+			}
+		});
+	}
+
+	/**
+	 * Adds zoom in and out handlers to the timeline module
+	 */
+	private void addZoomHandlers() {
+		display.getZoomIn().addClickHandler(new ClickHandler() {
+
+			public void onClick(final ClickEvent event) {
+				// call zoom in on the timeline widget
+				display.getTimeline().zoomIn();
+			}
+		});
+
+		display.getZoomOut().addClickHandler(new ClickHandler() {
+
+			public void onClick(final ClickEvent event) {
+				// call zoom in on the timeline widget
+				display.getTimeline().zoomOut();
+			}
+		});
+	}
+
+	/**
+	 * calling the server for the initial data setup
+	 */
+	private void doInitialSetup() {
+		// TODO: this result can be cached quite successfully on the server
+		// (perhaps in the dispatch module
+		dispatcher.execute(new GetTimelineUISetupCommand(), new DisplayCallback<GetTimelineUISetupResult>(
+				display) {
+
+			@Override
+			protected void handleFailure(final Throwable e) {
+				Log.debug("Unable to initialise UI", e);
+			}
+
+			@Override
+			protected void handleSuccess(final GetTimelineUISetupResult setupData) {
+				Log.debug("Succesfully got timeline setup data");
+				setupTimeline(setupData);
+			}
+		});
+	}
+
+	@Override
+	protected void onBind() {
+		// TODO: all those anonymous classes make the code rather untidy... can
+		// we possible put all this somewhere else?
+		doInitialSetup();
+		addScrollHandler();
+		addZoomHandlers();
+		addScriptureChangeHandler();
+	}
+
+	@Override
+	protected void onPlaceRequest(final PlaceRequest request) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	protected void onUnbind() {
+		// TODO Auto-generated method stub
+
+	}
+
+	/**
+	 * sets up the timeline view, height, intial timebands, etc.
+	 * 
+	 * @param setupData data returned from the server including all the
+	 *            timebands, and their units, etc.
+	 */
+	protected void setupTimeline(final GetTimelineUISetupResult setupData) {
+		final 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.
+		// TODO: change TimelineBean to be a TimebandBean
+		for (final TimelineBean tb : setupData.getTimelines()) {
+			final Timeband band = new Timeband(timeline, tb.getTimelineId(), tb.getTimelineDescription());
+
+			band.setPixelsPerUnit(TimelineConstants.DEFAULT_PIXELS_PER_UNIT);
+			Log.debug("Unit of band is: " + tb.getUnit());
+			band.setOriginalUnit(Unit.valueOf(tb.getUnit()));
+			band.setCurrentDate(TimelineConstants.INITIAL_DATE);
+			band.setCurrentDateX(TimelineConstants.TIMELINE_WIDTH);
+			timeline.addBand(band);
+		}
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/eventbus/StepEventBusImpl.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/eventbus/StepEventBusImpl.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/eventbus/StepEventBusImpl.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,23 @@
+package com.tyndalehouse.step.web.client.service.eventbus;
+
+import net.customware.gwt.presenter.client.DefaultEventBus;
+
+import com.allen_sauer.gwt.log.client.Log;
+import com.google.gwt.event.shared.GwtEvent;
+
+/**
+ * Default Step event bus to be used. Provides extra logging and in flight
+ * monitoring capability later
+ * 
+ * @author cjburrell
+ * 
+ */
+public class StepEventBusImpl extends DefaultEventBus {
+
+	@Override
+	public void fireEvent(final GwtEvent<?> event) {
+		Log.debug("StepEventBus:: firing event " + event.toDebugString());
+		super.fireEvent(event);
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/refdata/ModuleName.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/refdata/ModuleName.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/refdata/ModuleName.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,63 @@
+package com.tyndalehouse.step.web.client.service.refdata;
+
+/**
+ * Bean representing a module and its direct parent (if there is a hierarchy
+ * 
+ * @author cjburrell
+ * 
+ */
+public class ModuleName {
+	/**
+	 * Module name
+	 */
+	private String moduleName;
+
+	/**
+	 * Parent if applicable of the module
+	 */
+	private String parent;
+
+	/**
+	 * Cosntructs a module with a given name and parent
+	 * 
+	 * @param moduleName module name
+	 * @param parent parent may be null
+	 */
+	public ModuleName(final String moduleName, final String parent) {
+		this.moduleName = moduleName;
+
+		if (parent == null) {
+			this.parent = "Module";
+		} else {
+			this.parent = parent;
+		}
+	}
+
+	/**
+	 * @return the moduleName
+	 */
+	public String getModuleName() {
+		return moduleName;
+	}
+
+	/**
+	 * @return the parent
+	 */
+	public String getParent() {
+		return parent;
+	}
+
+	/**
+	 * @param moduleName the moduleName to set
+	 */
+	public void setModuleName(final String moduleName) {
+		this.moduleName = moduleName;
+	}
+
+	/**
+	 * @param parent the parent to set
+	 */
+	public void setParent(final String parent) {
+		this.parent = parent;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/refdata/ModuleRefData.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/refdata/ModuleRefData.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/service/refdata/ModuleRefData.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,100 @@
+package com.tyndalehouse.step.web.client.service.refdata;
+
+import java.util.ArrayList;
+import java.util.List;
+
+//TODO: remove singleton pattern and use @Singleton and Gin instead.
+/**
+ * Client side service to serve the reference data to the user
+ */
+// TODO: Ginify the singleton pattern
+public final class ModuleRefData {
+	/**
+	 * This class is a singleton, so this is the unique private instance
+	 */
+	private static ModuleRefData instance;
+
+	/**
+	 * List of depths populating the Depth dropdown (level at which the user
+	 * wants to see articles)
+	 */
+	private final List<String> depths;
+
+	/**
+	 * List of module names to be displayed in the drop downs
+	 */
+	private final List<ModuleName> moduleNames;
+
+	/**
+	 * Private constructor setting up all modules, and their hierarchies For
+	 * e.g. People, Events and Eras come under History TODO: This needs
+	 * internationalising
+	 */
+	private ModuleRefData() {
+		moduleNames = new ArrayList<ModuleName>();
+
+		// no hashtable on client side...
+
+		// History Modules
+		moduleNames.add(new ModuleName("People", "History"));
+		moduleNames.add(new ModuleName("Events", "History"));
+		moduleNames.add(new ModuleName("Eras", "History"));
+
+		// Geography Modules
+		moduleNames.add(new ModuleName("Places", "Geography"));
+		moduleNames.add(new ModuleName("Maps", "Geography"));
+		moduleNames.add(new ModuleName("Google Maps", "Geography"));
+
+		// Main modules
+		// TODO: tidy up and send to paremeter files
+		moduleNames.add(new ModuleName("History", "Module"));
+		moduleNames.add(new ModuleName("Geography", "Module"));
+		moduleNames.add(new ModuleName("Language", "Module"));
+		moduleNames.add(new ModuleName("Parallels", "Module"));
+		moduleNames.add(new ModuleName("Translations", "Module"));
+		moduleNames.add(new ModuleName("Commentaries", "Module"));
+		moduleNames.add(new ModuleName("Publications", "Module"));
+		moduleNames.add(new ModuleName("Presentations", "Module"));
+
+		// DEPTHS
+		depths = new ArrayList<String>();
+		depths.add("Quick Look");
+		depths.add("Deep Study");
+		depths.add("Scholarly Details");
+	}
+
+	/**
+	 * @return the instance
+	 */
+	public static synchronized ModuleRefData getInstance() {
+		if (instance == null) {
+			instance = new ModuleRefData();
+		}
+
+		return instance;
+	}
+
+	/**
+	 * @return the depths
+	 */
+	public List<String> getDepths() {
+		return depths;
+	}
+
+	/**
+	 * Returns a list of modules given a parent module
+	 * 
+	 * @param parentModule parent module, or "Module" if none
+	 * @return the list of available modules
+	 */
+	public List<String> getListOfModules(final String parentModule) {
+		final List<String> subset = new ArrayList<String>();
+
+		for (final ModuleName mn : moduleNames) {
+			if (mn.getParent().equals(parentModule)) {
+				subset.add(mn.getModuleName());
+			}
+		}
+		return subset;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/HasSource.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/HasSource.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/HasSource.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,24 @@
+package com.tyndalehouse.step.web.client.toolkit;
+
+/**
+ * Indicates that the view (generally) has got a source, a dropdown list for
+ * e.g.) and can be set
+ * 
+ * @author cjburrell
+ * 
+ * @param <T> The type of data it is expecting
+ */
+public interface HasSource<T> {
+	/**
+	 * Clears the source, i.e. resets to an empty list
+	 */
+	void clearSource();
+
+	/**
+	 * Settings the data
+	 * 
+	 * @param source source of the data
+	 */
+	void setSource(T source);
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/HtmlList.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/HtmlList.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/HtmlList.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,114 @@
+package com.tyndalehouse.step.web.client.toolkit;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.google.gwt.dom.client.Document;
+import com.google.gwt.dom.client.Element;
+import com.google.gwt.dom.client.LIElement;
+import com.google.gwt.user.client.Command;
+import com.google.gwt.user.client.Event;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * A HTML list, taken partially from the web This can be ordered or unordered
+ * 
+ * @author cjburrell
+ */
+public class HtmlList extends Widget {
+	/**
+	 * Two types of list, ordered or undered
+	 * 
+	 * @author cjburrell
+	 * 
+	 */
+	public static enum ListType {
+		/**
+		 * An ordered list
+		 */
+		ORDERED {
+			/**
+			 * Creates an UL element on the DOM
+			 * 
+			 * @return the element created
+			 */
+			@Override
+			public Element createElement() {
+				return Document.get().createOLElement();
+			}
+		},
+		/**
+		 * An unordered list
+		 */
+		UNORDERED {
+			/**
+			 * Creates an UL element on the DOM
+			 * 
+			 * @return the element created
+			 */
+			@Override
+			public Element createElement() {
+				return Document.get().createULElement();
+			}
+		};
+
+		/**
+		 * Creates an UL element on the DOM
+		 * 
+		 * @return the element created
+		 */
+		public abstract Element createElement();
+	}
+
+	/**
+	 * list of items to be mapped in the list. And whether they should launch
+	 * Commands on selected
+	 */
+	private final Map<Element, Command> listItems = new HashMap<Element, Command>();
+
+	/**
+	 * Constructor to create a HTML unordered or ordered list
+	 * 
+	 * @param listType whether an ordered or unordered list should be created
+	 */
+	public HtmlList(final ListType listType) {
+		setElement(listType.createElement());
+		setStylePrimaryName("html-list");
+	}
+
+	/**
+	 * Adds an item to the HtmlList
+	 * 
+	 * @param text the text next to the bullet/numbered point
+	 * @param command the command to be executed if a user clicks on it
+	 */
+	public void addItem(final String text, final Command command) {
+		final LIElement liElement = Document.get().createLIElement();
+		liElement.setInnerText(text);
+		getElement().appendChild(liElement);
+
+		listItems.put(liElement, command);
+
+		// All the events we're interested in
+		sinkEvents(Event.ONMOUSEOVER | Event.ONMOUSEOUT | Event.ONCLICK);
+	}
+	//	
+	// @Override
+	// public void onBrowserEvent(Event event) {
+	// switch(event.getTypeInt()) {
+	// case Event.ONCLICK:
+	// Element target = event.getTarget();
+	// if (listItems.containsKey(target))
+	// DeferredCommand.addCommand(listItems.get(target));
+	//
+	// break;
+	// case Event.ONMOUSEOUT:
+	// event.getTarget().setClassName(null);
+	// break;
+	//				
+	// case Event.ONMOUSEOVER:
+	// event.getTarget().setClassName("highlightOn");
+	// break;
+	// }
+	// }
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/SimpleListBox.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/SimpleListBox.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/SimpleListBox.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,27 @@
+package com.tyndalehouse.step.web.client.toolkit;
+
+import java.util.List;
+
+import com.google.gwt.user.client.ui.ListBox;
+
+/**
+ * An extension to the GWT ListBox, mainly to allow the setSource method
+ * exposure, and hide implementation details of the ListBox from the presenter
+ * 
+ * @author cjburrell
+ * 
+ */
+public class SimpleListBox extends ListBox implements HasSource<List<String>> {
+
+	public void clearSource() {
+		this.clear();
+
+	}
+
+	public void setSource(final List<String> source) {
+		clearSource();
+		for (final String key : source) {
+			addItem(key);
+		}
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/SourceListBox.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/SourceListBox.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/SourceListBox.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,28 @@
+package com.tyndalehouse.step.web.client.toolkit;
+
+import java.util.SortedMap;
+import java.util.Map.Entry;
+
+import com.google.gwt.user.client.ui.ListBox;
+
+/**
+ * Similar to @see {@link SimpleListBox}, but the source is given as a HashMap
+ * 
+ * @author cjburrell
+ * 
+ */
+public class SourceListBox extends ListBox implements HasSource<SortedMap<String, String>> {
+
+	public void clearSource() {
+		this.clear();
+
+	}
+
+	public void setSource(final SortedMap<String, String> source) {
+		clearSource();
+		for (final Entry<String, String> entry : source.entrySet()) {
+			addItem(entry.getValue(), entry.getKey());
+		}
+
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/scripture/ScriptureDisplayConstants.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/scripture/ScriptureDisplayConstants.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/scripture/ScriptureDisplayConstants.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,22 @@
+package com.tyndalehouse.step.web.client.toolkit.scripture;
+
+/**
+ * Scripture display module constants
+ * 
+ * @author cjburrell
+ * 
+ */
+public final class ScriptureDisplayConstants {
+
+	/**
+	 * To emphasis text in the module, for e.g. when a user clicks on a word
+	 */
+	public static final String EMPHASISE = "scripture-emphasise";
+
+	/**
+	 * making constructor private
+	 */
+	private ScriptureDisplayConstants() {
+
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/scripture/VerseLabel.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/scripture/VerseLabel.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/scripture/VerseLabel.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,132 @@
+package com.tyndalehouse.step.web.client.toolkit.scripture;
+
+import java.util.List;
+
+import net.customware.gwt.presenter.client.EventBus;
+
+import com.allen_sauer.gwt.log.client.Log;
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.tyndalehouse.step.web.client.event.LemmaClickedEvent;
+
+/**
+ * Composite wrapper around a portion of scriptural text. The wrapper contains
+ * data retrieved from the server such as lemmas (Strong numbers), morphological
+ * data and an alternative word in the case of an interlinear
+ * 
+ * @author cjburrell
+ * 
+ */
+public class VerseLabel extends Composite {
+	/**
+	 * if there is an interlinear, then this is where the alternative word is
+	 * stored
+	 */
+	private Label alternativeWord;
+
+	/**
+	 * TODO: this should be removed into the presenter the event bus to fire off
+	 * events
+	 */
+	private final EventBus eventBus;
+
+	/**
+	 * Flow panel for display
+	 */
+	private final FlowPanel fp;
+
+	/**
+	 * List of Strong numbers associated to this portion of text
+	 */
+	private List<String> lemmas;
+
+	/**
+	 * The main word(s) to be displayed
+	 */
+	private final Label mainWord;
+
+	/**
+	 * list of morphs associated to this wrapper of text
+	 */
+	private List<String> morphs;
+
+	/**
+	 * This constructors initialises an instance of the composite wrapper and
+	 * sets up the panel, css, etc.
+	 * 
+	 * @param text the text to be wrapped
+	 * @param eventBus the event bus if events are to be fired
+	 */
+	public VerseLabel(final String text, final EventBus eventBus) {
+		fp = new FlowPanel();
+
+		// TODO: store all strings to do with css somewhere central
+		fp.setStyleName("scripture-interlinear");
+		initWidget(fp);
+
+		// main word display (from the version selected)
+		mainWord = new Label(text);
+		fp.add(mainWord);
+
+		this.eventBus = eventBus;
+	}
+
+	/**
+	 * @return the lemma
+	 */
+	public List<String> getLemma() {
+		return lemmas;
+	}
+
+	/**
+	 * @return the morph
+	 */
+	public List<String> getMorph() {
+		return morphs;
+	}
+
+	/**
+	 * sets the alternative word. This could be a Hebrew word, but for a classic
+	 * interlinear it could also be a English word, where the main word is the
+	 * Hebrew
+	 * 
+	 * @param originalWord an original word (for e.g. a hebrew translation)
+	 */
+	public void setAlternativeWord(final String originalWord) {
+		if (alternativeWord != null) {
+			alternativeWord.setText(originalWord);
+			return;
+		}
+
+		alternativeWord = new Label(originalWord);
+		fp.add(alternativeWord);
+	}
+
+	/**
+	 * @param lemma the lemma to set
+	 */
+	public void setLemmas(final List<String> lemma) {
+		this.lemmas = lemma;
+
+		if (lemma != null) {
+			// add a click listener
+			mainWord.addClickHandler(new ClickHandler() {
+
+				public void onClick(final ClickEvent event) {
+					Log.debug("Firing event");
+					eventBus.fireEvent(new LemmaClickedEvent(lemma));
+				}
+			});
+		}
+	}
+
+	/**
+	 * @param morph the morph to set
+	 */
+	public void setMorphs(final List<String> morph) {
+		this.morphs = morph;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TapeTrack.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TapeTrack.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TapeTrack.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,111 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * A tape track is the track on which events are painted. The events are
+ * contained by the TimeBand as that's where they logically reside. However,
+ * they are painted on the timetracks.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class TapeTrack extends Widget {
+	/**
+	 * The following variable defines the earliest spot at which an event can be
+	 * painted
+	 */
+	private int earliestPaintOpportunity;
+
+	/**
+	 * Determines whether the Tape Track is part of the DOM yet
+	 */
+	private boolean isRendered;
+
+	/**
+	 * The following spot defines the latest spot at which an event needs to be
+	 * finished if it is to be painted on this track
+	 */
+	private int latestPaintOpportunity;
+
+	/**
+	 * Element on the DOM that is the track
+	 */
+	private final Element track;
+
+	/**
+	 * The default constructor initialises in memory a tape track. This includes
+	 * setting up the div outside of the DOM, and setting the default earliest
+	 * and latest opportunities for painting as Max and Min Integers hence
+	 * allowing everything to be painted
+	 */
+	public TapeTrack() {
+		isRendered = false;
+		track = DOM.createDiv();
+		track.setClassName("step-tape-track");
+		earliestPaintOpportunity = Integer.MAX_VALUE;
+		latestPaintOpportunity = Integer.MIN_VALUE;
+
+		setElement(track);
+	}
+
+	/**
+	 * Checks and then adds an event to the timetrack Logically it is still
+	 * added to the band, but it is painted on the timetrack
+	 * 
+	 * @param event even to be painted
+	 * @return whether the event has been painted
+	 */
+	public boolean addEvent(final TimeEvent event) {
+		if (canPaintAt(event.getLeftPixelPosition(), event.getTotalWidth())) {
+			// Log.debug(event.getDescription() +
+			// " can be painted on timetrack");
+			event.paint(this);
+
+			// now update the available bands
+			// Log.debug("Old latest and earliest times were: " +
+			// latestPaintOpportunity + "," + earliestPaintOpportunity);
+			latestPaintOpportunity = Math.max(latestPaintOpportunity, event.getLeftPixelPosition()
+					+ event.getTotalWidth());
+			earliestPaintOpportunity = Math.min(earliestPaintOpportunity, event.getLeftPixelPosition());
+			// Log.debug("New latest and earliest times were: " +
+			// latestPaintOpportunity + "," + earliestPaintOpportunity);
+			return true;
+		}
+		return false;
+	}
+
+	/**
+	 * The events need to be added in order, otherwise the time taping will not
+	 * be efficient Returns whether an event of width width can be painted at
+	 * position pixel
+	 * 
+	 * @param pixel pixel position at which to be painted
+	 * @param width width of the event
+	 * @return true if the event can be painted
+	 */
+	public boolean canPaintAt(final int pixel, final int width) {
+		return pixel > latestPaintOpportunity || (pixel + width + 1) < earliestPaintOpportunity;
+	}
+
+	/**
+	 * @return the track
+	 */
+	public Element getTrack() {
+		return track;
+	}
+
+	/**
+	 * paints the timetrack on to the timeband
+	 * 
+	 * @param band the band to be painteds
+	 */
+	public void paint(final Timeband band) {
+		if (!isRendered) {
+			band.getBandDiv().appendChild(track);
+			isRendered = true;
+		}
+	}
+}

Added: 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	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeEvent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,396 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+import com.extjs.gxt.ui.client.core.El;
+import com.extjs.gxt.ui.client.util.TextMetrics;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.tyndalehouse.step.web.client.toolkit.timeline.components.TimelineConstants;
+import com.tyndalehouse.step.web.client.toolkit.timeline.helpers.TimeConversionUtil;
+
+/**
+ * A time event, to be positioned on the screen
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimeEvent {
+
+	/**
+	 * events can move from one timeband to another
+	 */
+	private final Timeband currentTimeband;
+
+	/**
+	 * description of the event
+	 */
+	private String description;
+
+	/**
+	 * If this event is a duration, this captures the width to be displayed
+	 */
+	private int durationWidth;
+
+	/**
+	 * The master div containing all the relevant DOM elements representing it
+	 */
+	private Element eventDiv;
+
+	/**
+	 * default to a standard event or duration we will drive this from the
+	 * database
+	 */
+	private String eventType;
+
+	/**
+	 * The picture if appropriate, displaying the type of event
+	 */
+	private Element icon;
+	/**
+	 * id of the event
+	 */
+	private int id;
+
+	/**
+	 * whether the time event has been rendered on to the DOM yet
+	 */
+	private boolean isRendered = false;
+
+	/**
+	 * The label containing the text going with the event
+	 */
+	private Element label;
+
+	/**
+	 * The left-most position at which the event is located, in relation to the
+	 * timeband
+	 */
+	private int leftPixelPosition;
+	/**
+	 * the end date of a duration event
+	 */
+	private Long maxDate;
+
+	/**
+	 * the date of the event, and if a duration, the start date
+	 * 
+	 */
+	private Long minDate;
+
+	/**
+	 * Show event text
+	 */
+	private boolean showText;
+
+	/**
+	 * A representation of the total width occupied by the event, including the
+	 * text next to it. This is particularly important for events that are
+	 * single point in time, where the text will be much wider than the icon
+	 * 
+	 */
+	private int totalWidth;
+
+	/**
+	 * The
+	 * 
+	 * @param id id of the event
+	 * @param description a description to be displayed
+	 * @param minDate a minimum date
+	 * @param maxDate a maximum date, optional, in case of single point in time
+	 *            events
+	 * @param tb the timeband
+	 */
+	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;
+		this.currentTimeband = tb;
+
+		setupEventSpecificOptions();
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(final Object obj) {
+		if (this == obj) {
+			return true;
+		}
+		if (obj == null) {
+			return false;
+		}
+		if (getClass() != obj.getClass()) {
+			return false;
+		}
+		final TimeEvent other = (TimeEvent) obj;
+		if (id != other.getId()) {
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * @return the description
+	 */
+	public String getDescription() {
+		return description;
+	}
+
+	/**
+	 * returns the event div that is shown on the screen
+	 * 
+	 * @return the eventDiv
+	 */
+	public Element getEventDiv() {
+		return eventDiv;
+	}
+
+	/**
+	 * @return the eventType
+	 */
+	public String getEventType() {
+		return eventType;
+	}
+
+	/**
+	 * @return the id
+	 */
+	public int getId() {
+		return id;
+	}
+
+	/**
+	 * @return the leftPixelPosition
+	 */
+	public int getLeftPixelPosition() {
+		return leftPixelPosition;
+	}
+
+	/**
+	 * @return the maxDate
+	 */
+	public Long getMaxDate() {
+		return maxDate;
+	}
+
+	/**
+	 * @return the minDate
+	 */
+	public long getMinDate() {
+		return minDate;
+	}
+
+	/**
+	 * @return the totalWidth
+	 */
+	public int getTotalWidth() {
+		return totalWidth;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#hashCode()
+	 */
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + id;
+		return result;
+	}
+
+	/**
+	 * returns whether this event is a duration or point in time event
+	 * 
+	 * @return true if this is a duration event
+	 */
+	public boolean isDuration() {
+		return maxDate == null;
+	}
+
+	/**
+	 * @return the isRendered
+	 */
+	public boolean isRendered() {
+		return isRendered;
+	}
+
+	/**
+	 * @return the showText
+	 */
+	public boolean isShowText() {
+		return showText;
+	}
+
+	/**
+	 * the main responsible culprit for painting events on the timeband
+	 * 
+	 * @param track the track on which the event will be painted
+	 */
+	public void paint(final TapeTrack track) {
+		// all we do is attach it to the parent if need be.
+		if (!isRendered) {
+			setupDivProperties();
+			track.getTrack().appendChild(eventDiv);
+			isRendered = true;
+		}
+	}
+
+	/**
+	 * ensures the event gets rendered next time paint() is called
+	 */
+	public void reset() {
+		isRendered = false;
+
+		// also recalculate the times and dates of the events (perhaps this is
+		// not always necessary)
+		setupEventSpecificOptions(); // a few extra bits in there, but nothing
+		// that takes time
+	}
+
+	/**
+	 * @param description the description to set
+	 */
+	public void setDescription(final String description) {
+		this.description = description;
+	}
+
+	/**
+	 * @param eventType the eventType to set
+	 */
+	public void setEventType(final String eventType) {
+		this.eventType = eventType;
+	}
+
+	/**
+	 * @param id the id to set
+	 */
+	public void setId(final int id) {
+		this.id = id;
+	}
+
+	/**
+	 * @param leftPixelPosition the leftPixelPosition to set
+	 */
+	public void setLeftPixelPosition(final int leftPixelPosition) {
+		this.leftPixelPosition = leftPixelPosition;
+	}
+
+	/**
+	 * @param maxDate the maxDate to set
+	 */
+	public void setMaxDate(final long maxDate) {
+		this.maxDate = maxDate;
+	}
+
+	/**
+	 * @param maxDate the maxDate to set
+	 */
+	public void setMaxDate(final Long maxDate) {
+		this.maxDate = maxDate;
+	}
+
+	/**
+	 * @param minDate the minDate to set
+	 */
+	public void setMinDate(final long minDate) {
+		this.minDate = minDate;
+	}
+
+	/**
+	 * @param minDate the minDate to set
+	 */
+	public void setMinDate(final Long minDate) {
+		this.minDate = minDate;
+	}
+
+	/**
+	 * @param showText the showText to set
+	 */
+	public void setShowText(final boolean showText) {
+		this.showText = showText;
+	}
+
+	/**
+	 * Creates all the elements/styles/etc.
+	 */
+	private void setupDivProperties() {
+		eventDiv = DOM.createDiv();
+		icon = DOM.createDiv();
+		label = DOM.createDiv();
+		final El gxtEvent = new El(eventDiv);
+		final El gxtLabel = new El(label);
+
+		// setup div hierarchy
+		eventDiv.appendChild(icon);
+		eventDiv.appendChild(label);
+
+		// setup CSS properties
+		eventDiv.setClassName(TimelineConstants.EVENT);
+
+		// setup positioning
+		gxtEvent.setLeft(leftPixelPosition);
+
+		// setup values
+		label.setInnerText(description);
+
+		// specific properties
+		if (maxDate != null) {
+			setupDurationProperties();
+		} else {
+			setupPointInTimeProperties();
+		}
+
+		// all css is setup, take measurement of label element:
+
+		final TextMetrics ruler = TextMetrics.get();
+		ruler.bind(new El(label));
+		final int labelWidth = ruler.getWidth(description);
+		gxtLabel.setWidth(labelWidth);
+
+		// set up width: if event, then labelWidth, otherwise
+		// max(duration,label)
+		totalWidth = maxDate == null ? labelWidth : Math.max(durationWidth, labelWidth);
+		gxtEvent.setWidth(totalWidth);
+	}
+
+	/**
+	 * Sets up duration properties
+	 */
+	private void setupDurationProperties() {
+		final El gxtIcon = new El(icon);
+		final El gxtLabel = new El(label);
+		gxtIcon.setWidth(durationWidth);
+		gxtIcon.setStyleName(eventType, true);
+		gxtLabel.setStyleName(TimelineConstants.DURATION_LABEL, true);
+	}
+
+	/**
+	 * Sets up properties and fields that depend on the type of event
+	 */
+	private void setupEventSpecificOptions() {
+		this.leftPixelPosition = TimeConversionUtil.timeToPixel(minDate.longValue(), currentTimeband);
+		if (maxDate == null) {
+			// then it's a point in time
+			eventType = TimelineConstants.POINT_IN_TIME_EVENT;
+		} else {
+			eventType = TimelineConstants.DURATION;
+			durationWidth = Math.max(TimelineConstants.EVENT_MIN_WIDTH, TimeConversionUtil.timeToPixel(
+					maxDate.longValue(), currentTimeband)
+					- leftPixelPosition);
+		}
+	}
+
+	/**
+	 * Sets up point in time properties
+	 */
+	private void setupPointInTimeProperties() {
+		final El gxtLabel = new El(label);
+		gxtLabel.setStyleName(TimelineConstants.POINT_IN_TIME_LABEL, true);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeEventDescriptor.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeEventDescriptor.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/TimeEventDescriptor.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,82 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+import com.extjs.gxt.ui.client.core.El;
+import com.google.gwt.event.dom.client.MouseEvent;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.tyndalehouse.step.web.client.toolkit.timeline.components.TimelineConstants;
+
+/**
+ * There is only one TimeEvent descriptor for the timeline module. This is the
+ * hover over the time event on the timeline module. For e.g. a user might over
+ * a point in time event, and get a description of what/when it represents
+ * 
+ * @author cjburrell
+ * 
+ */
+public class TimeEventDescriptor {
+
+	/**
+	 * DOM Element containing the time event description
+	 */
+	private final Element div;
+
+	/**
+	 * a wrapper (div) around the main element
+	 */
+	private final El divWrapper;
+
+	/**
+	 * The timeline component on which to draw the popup
+	 */
+	private final Timeline timeline;
+
+	/**
+	 * public constructor initialising the descriptor
+	 * 
+	 * @param timeline the timeline on which the popup is to be displayed
+	 */
+	public TimeEventDescriptor(final Timeline timeline) {
+		this.timeline = timeline;
+		div = DOM.createDiv();
+		divWrapper = new El(div);
+
+		divWrapper.setStyleName("step-timeline-time-event-descriptor");
+		divWrapper.setDisplayed(false);
+
+		// append to timeline component
+		timeline.getElement().appendChild(div);
+	}
+
+	/**
+	 * @return the divWrapper
+	 */
+	public El getDivWrapper() {
+		return divWrapper;
+	}
+
+	/**
+	 * Hides the timeline
+	 */
+	public void hide() {
+		getDivWrapper().setDisplayed(false);
+	}
+
+	/**
+	 * Given a timed event, this shows the description in a div
+	 * 
+	 * @param te the TimeEvent to be displayed
+	 * @param me the mouse event that was triggered, contains details of pixel
+	 *            positions
+	 */
+	public void show(final TimeEvent te, final MouseEvent<?> me) {
+		final El divWrapper = getDivWrapper();
+		divWrapper.setInnerHtml(te.getId() + " - " + te.getDescription());
+		divWrapper.setDisplayed(true);
+		// Log.debug("x: " + me.getX());
+		// Log.debug("y: " + me.getY());
+
+		divWrapper.setLeft(timeline.getAbsoluteLeft() + me.getX());
+		divWrapper.setTop(timeline.getAbsoluteTop() + me.getY() - TimelineConstants.SPACE_BELOW_POPUP);
+	}
+}

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	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,164 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+import java.util.HashMap;
+
+import com.extjs.gxt.ui.client.core.El;
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.tyndalehouse.step.web.client.toolkit.timeline.helpers.TimeConversionUtil;
+import com.tyndalehouse.step.web.shared.timeline.Unit;
+
+/**
+ * time scale, in charge of drawing the different columns on the timeband at
+ * various lengths, dependant on the uni of the timeband
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimeScale {
+	/**
+	 * timeband on which the TimeScale resides
+	 */
+	private final Timeband band;
+
+	/**
+	 * true if time scale rendered
+	 */
+	private boolean isRendered = false;
+
+	/**
+	 * Maps of all timescales that have been drawn on the timeband
+	 */
+	private final HashMap<Integer, Element> paintedTimescaleBands;
+
+	/**
+	 * DOM element containing the scale columns
+	 */
+	private Element scaleBand;
+
+	/**
+	 * A timescale is attached to a timeband
+	 * 
+	 * @param band timeband to attach the scale on
+	 */
+	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;
+		}
+
+		// if rendered already? skip!
+		if (!isRendered) {
+			scaleBand = DOM.createDiv();
+			paintedTimescaleBands.clear(); // reset in case we're in a zoom
+
+			final 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();
+	}
+
+	/**
+	 * The easy way is to get rid of everything and repaint The slightly more
+	 * clever way is to actually repaint the existing dom elements. It uses more
+	 * memory though, however, we can try both eventually if need be.
+	 */
+	public void repaint() {
+		// remove oneself first
+		reset();
+		paint();
+	}
+
+	/**
+	 * resets to redraw
+	 */
+	public void reset() {
+		isRendered = false;
+	}
+
+	/**
+	 * draws the segments on the TimeScale DOM element
+	 * 
+	 * @param firstVisibleSegmentPixel first visible pixel, left most, of the
+	 *            band
+	 * @param numberOfVisibleSegments number of segments to draw
+	 */
+	private synchronized void drawSegments(final long firstVisibleSegmentPixel,
+			final long numberOfVisibleSegments) {
+		final El gxtScaleBand = new El(scaleBand);
+		final 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...
+			final Integer key = Integer.valueOf(relativeLeft);
+			final Integer keyMinus1 = Integer.valueOf(relativeLeft - 1);
+			final Integer keyPlus1 = Integer.valueOf(relativeLeft + 1);
+
+			// due to rounding errors, we need to check 1 below key and 1 above
+			// too
+			// TODO: instead of relying on time for drawing these, draw the
+			// first one,
+			// then rely on intervals. Saves computations for storage.
+			if (!paintedTimescaleBands.containsKey(key) && !paintedTimescaleBands.containsKey(keyPlus1)
+					&& !paintedTimescaleBands.containsKey(keyMinus1)) {
+				final Element un = DOM.createDiv();
+				final El gxtUn = new El(un);
+				gxtUn.setWidth(pixelsPerUnit);
+
+				un.setInnerText(TimeConversionUtil.formatPixelToTime(relativeLeft, band));
+				gxtScaleBand.appendChild(un);
+
+				// set left position:
+				gxtUn.setLeft(relativeLeft);
+				gxtUn.setTop(0); // if this is laid out after events, then 0
+				// makes sure it lines up to the top
+				gxtUn.setHeight("100%");
+
+				paintedTimescaleBands.put(key, un);
+			}
+			// else {
+			// TODO: log should come in next
+			// Log.debug("Segment not drawn as already painted");
+			// }
+			relativeLeft += pixelsPerUnit;
+		}
+	}
+
+	/**
+	 * paints the visible segments (columns) on to the band This method mainly
+	 * sets up all the relevant mathematics, and passes down
+	 */
+	private void paintVisibleScale() {
+		final long visibleLeft = band.getMinVisibleDate();
+		final long visibleRight = band.getMaxVisibleDate();
+
+		final 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
+		final long numberOfVisibleSegments = (visibleRight - visibleLeft) / unit.getMilliseconds();
+
+		// first visible segment is going to be located at
+		final 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);
+	}
+}

Added: 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	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/Timeband.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,952 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+import java.util.ArrayList;
+import java.util.List;
+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.client.toolkit.timeline.components.TimebandRequestWindow;
+import com.tyndalehouse.step.web.client.toolkit.timeline.components.TimelineConstants;
+import com.tyndalehouse.step.web.client.toolkit.timeline.exceptions.CannotDeleteEventException;
+import com.tyndalehouse.step.web.client.toolkit.timeline.exceptions.IncapableOfCalculatingRequestWindowException;
+import com.tyndalehouse.step.web.client.toolkit.timeline.helpers.TimeConversionUtil;
+import com.tyndalehouse.step.web.shared.common.timeline.TimeBandVisibleDate;
+import com.tyndalehouse.step.web.shared.timeline.Unit;
+
+/**
+ * The TimeBand object represents a section of the timeline that contains the
+ * events. There are many timebands on the timeline. Timebands contain
+ * TimeScales representing units as well as TapeTracks which contain the events
+ * The events are logically held on the Timeband, but painted on the time track.
+ * 
+ * @author CJBurrell
+ */
+public class Timeband extends Widget {
+	/**
+	 * The DOM element containing all timeband elements
+	 */
+	private Element bandDiv;
+
+	/**
+	 * The current date that is shown
+	 */
+	private long currentDate;
+
+	/**
+	 * The current pixel on the timeband representing the current date (above)
+	 */
+	private long currentDateX = 0;
+
+	/**
+	 * 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;
+
+	/**
+	 * The timeband description
+	 */
+	private String description;
+
+	/**
+	 * this contains all the events on the time band
+	 */
+	private final TreeMap<Integer, TimeEvent> events;
+
+	/**
+	 * Id of the timeband
+	 */
+	private int id;
+
+	/**
+	 * This indicates whether the band has been painted and is showing
+	 */
+	private boolean isRendered = false;
+
+	/**
+	 * whether the user is interested in this timeband or not
+	 */
+	private boolean isUserInterested;
+
+	/**
+	 * Max date that the timeband is expected to paint
+	 */
+	private long maxDate;
+
+	/**
+	 * Min date that the timeband is expected to paint
+	 */
+	private long minDate;
+
+	/**
+	 * The last recorded mouse position on the mouse down event
+	 */
+	private int mouseDownScrollLeft;
+
+	/**
+	 * original unit as set up before it was rendered for the first time This is
+	 * used so that we can revert back to the original, recommended unit at
+	 * point in time
+	 */
+	private Unit originalUnit = 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 = TimelineConstants.MINIMUM_UNIT_PORTION_BEFORE_SERVER_CALL;
+
+	/**
+	 * this is the parent widget Timeline object
+	 */
+	private final Timeline parent;
+
+	/**
+	 * Number of pixels to be shown per unit
+	 */
+	private int pixelsPerUnit;
+
+	/**
+	 * Each timeband is given a request window. This object is responsible of
+	 * working out how much to request from the server, so as not to flood it
+	 * with requests of stuff it already has
+	 */
+	private TimebandRequestWindow requestWindow = null;
+
+	/**
+	 * Whether or not to show the scale band
+	 */
+	private boolean showScale = true;
+
+	/**
+	 * The list of tape tracks on this timeband.
+	 */
+	private final List<TapeTrack> tapeTracks;
+
+	/**
+	 * The timeband container which contains the bandDiv
+	 */
+	private final Element timebandContainer;
+
+	/**
+	 * label of the timeband
+	 */
+	private Element timebandLabel;
+
+	/**
+	 * This is the timescale visible on the timeband drawing lines across the
+	 * timebands for each unit
+	 */
+	private TimeScale timescale;
+
+	/**
+	 * Determines the unit of the timeband and how to convert from/to
+	 * time/pixels
+	 */
+	private Unit unit;
+
+	/**
+	 * 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 = TimelineConstants.ZOOM_FACTOR;
+
+	/**
+	 * To create a new timeband on the timeline
+	 * 
+	 * @param parent the timeline on which it is to be created
+	 * @param id the id of the timeband
+	 * @param description its description
+	 */
+	public Timeband(final Timeline parent, final int id, final String description) {
+		this.parent = parent;
+		this.id = id;
+		this.description = description;
+
+		// set up collections
+		events = new TreeMap<Integer, TimeEvent>();
+		tapeTracks = new ArrayList<TapeTrack>();
+
+		// set up page properties
+		bandDiv = DOM.createDiv();
+		timebandContainer = DOM.createDiv();
+		bandDiv.setClassName("step-timeband");
+		setElement(timebandContainer);
+	}
+
+	/**
+	 * Adds an event to the timeband, and therefore on to a random timetack. The
+	 * first available spot to minimize the space required. In particular this
+	 * delegates to addEventToTapeTrack after checking the event is not already
+	 * in our list of events
+	 * 
+	 * @param event event to be added
+	 */
+	public void addEvent(final TimeEvent event) {
+		// need to check the event isn't already in our list:
+		if (!events.containsKey(event.getId())) {
+			events.put(event.getId(), event);
+			addEventToTapeTrack(event);
+
+			// TODO: analyse this, but it is likely that it is not possible
+			// that the bit in the middle is redundant
+			if (isEventInVisibleSection(event)) {
+				Log.debug("Adding event to hidden band: " + event.getDescription());
+				addEventToTapeTrack(event);
+			}
+			// otherwise, autoHide is set to false, so leave hidden
+		}
+	}
+
+	/**
+	 * 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 maxDateRequested the maximum date that was requested and retrieved
+	 *            from the back-end
+	 */
+	public void adjustRequestedView(final long minDateRequested, final long maxDateRequested) {
+		if (requestWindow == null) {
+			requestWindow = new TimebandRequestWindow(minDateRequested, maxDateRequested);
+		} else {
+			requestWindow.adjustRange(minDateRequested, maxDateRequested);
+		}
+	}
+
+	/**
+	 * when a mousedown event has been captured, update the position at which
+	 * the mouse was
+	 * 
+	 * @param e the mousedown event
+	 */
+	public void captureScrollLeft(final MouseDownEvent e) {
+		this.mouseDownScrollLeft = timebandContainer.getScrollLeft();
+	}
+
+	/**
+	 * @return the bandDiv
+	 */
+	public Element getBandDiv() {
+		return bandDiv;
+	}
+
+	/**
+	 * @return the currentDate
+	 */
+	public long getCurrentDate() {
+		return currentDate;
+	}
+
+	/**
+	 * @return the currentDateX
+	 */
+	public long getCurrentDateX() {
+		return currentDateX;
+	}
+
+	/**
+	 * @return the description
+	 */
+	public String getDescription() {
+		return description;
+	}
+
+	/**
+	 * @return the events
+	 */
+	public TreeMap<Integer, TimeEvent> getEvents() {
+		return events;
+	}
+
+	/**
+	 * @return the id
+	 */
+	public int getId() {
+		return id;
+	}
+
+	/**
+	 * @return the maxDate
+	 */
+	public long getMaxDate() {
+		return maxDate;
+	}
+
+	/**
+	 * returns the current maximum visible date on the band
+	 * 
+	 * @return the maximum date visible on the band
+	 */
+	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);
+	}
+
+	/**
+	 * @return the minDate, in pixels
+	 */
+	public long getMinDate() {
+		return minDate;
+	}
+
+	/**
+	 * returns the current minimum visible date on the band
+	 * 
+	 * @return the minimum date visible on the band
+	 */
+	public long getMinVisibleDate() {
+		return TimeConversionUtil.pixelToTime(timebandContainer.getScrollLeft(), this);
+	}
+
+	/**
+	 * Could this be optimized by organising the events in time order, and on
+	 * scroll recording which events have popped off?
+	 * 
+	 * @return the number of visible events in the band
+	 */
+	public int getNumberOfVisibleEvents() {
+		int count = 0;
+		for (final TimeEvent te : events.values()) {
+			if (isEventInVisibleSection(te)) {
+				count++;
+			}
+		}
+		return count;
+	}
+
+	/**
+	 * Works out how much of the timeband is to be requested Ideally we should
+	 * TODO: this somewhere else.
+	 * 
+	 * @return the visible section of the timeband
+	 * @throws IncapableOfCalculatingRequestWindowException thrown if we are not
+	 *             in a position to calculate what the remaining section is.
+	 */
+	public TimeBandVisibleDate getOustandingTimebandPeriod()
+			throws IncapableOfCalculatingRequestWindowException {
+		final long minVisibleDate = getMinVisibleDate();
+		final long maxVisibleDate = getMaxVisibleDate();
+		final 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)!
+			// -------|--------$------|-----$--------------------
+			// mvd mrd Mvd Mrd
+			final long minReceivedDate = requestWindow.getMinDate();
+			final long maxReceivedDate = requestWindow.getMaxDate();
+			final boolean shiftedLeft = minVisibleDate < minReceivedDate;
+			final 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 so check that first:
+				if (maxVisibleDate < minReceivedDate) {
+					// we have issues here, as we're either going to have to
+					// remember about all the already painted stuff. this would
+					// potentially be troublesome
+					// as with units and zooming, we're going to have to
+					// eventually repaint huge amounts of stuff
+					// so reset to 0
+					requestWindow = null;
+
+					// TODO: investigate whether we want to clear the band down!
+					return new TimeBandVisibleDate(id, minVisibleDate, maxVisibleDate);
+				} 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) {
+					requestWindow = null;
+					return new TimeBandVisibleDate(id, minVisibleDate, maxVisibleDate);
+				} 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 {
+				throw new IncapableOfCalculatingRequestWindowException(minVisibleDate, maxVisibleDate,
+						minReceivedDate, maxReceivedDate);
+			}
+		}
+	}
+
+	/**
+	 * @return the outstandingUnitFactor
+	 */
+	public double getOutstandingUnitFactor() {
+		return outstandingUnitFactor;
+	}
+
+	/**
+	 * @return the pixelsPerUnit
+	 */
+	public int getPixelsPerUnit() {
+		return pixelsPerUnit;
+	}
+
+	/**
+	 * returns a single event contained on the timeband
+	 * 
+	 * @param eventId event id of the event
+	 * @return the TimeEvent
+	 */
+	public TimeEvent getSingleEvent(final String eventId) {
+		final Integer key = Integer.parseInt(eventId);
+		return events.get(key);
+	}
+
+	/**
+	 * current number of tape tracks on the band. Also remember that one tape
+	 * track is allocated at the top of the timeband to allow for dates to be
+	 * displayed
+	 * 
+	 * @return the numbers of tracks on the band
+	 */
+	public int getSizeTapeTracks() {
+		return tapeTracks.size();
+	}
+
+	/**
+	 * @return the unit
+	 */
+	public Unit getUnit() {
+		return unit;
+	}
+
+	/**
+	 * @return the zoomFactor
+	 */
+	public double getZoomFactor() {
+		return zoomFactor;
+	}
+
+	/**
+	 * Hides by setting the height of the band to 0
+	 */
+	public void hideFromUser() {
+		// set height to 0 by default, and we'll add something later TODO: to
+		// see which bands have got events...
+		new El(timebandContainer).setHeight(0);
+	}
+
+	/**
+	 * @return the deletionsDisabled
+	 */
+	public boolean isDeletionsDisabled() {
+		return deletionsDisabled;
+	}
+
+	/**
+	 * indicates whether the band has been rendered or not
+	 * 
+	 * @return true if the band has been rendered
+	 */
+	public boolean isRendered() {
+		return isRendered;
+	}
+
+	/**
+	 * @return the showScale
+	 */
+	public boolean isShowScale() {
+		return showScale;
+	}
+
+	/**
+	 * @return the isUserInterested
+	 */
+	public boolean isUserInterested() {
+		return isUserInterested;
+	}
+
+	/**
+	 * Does not delete the events but redraws everything else.
+	 */
+	public void redrawBand() {
+		tapeTracks.clear();
+
+		// use El to remove all children
+		new El(bandDiv).removeChildren();
+		resetAllEvents();
+
+		timescale.repaint();
+
+		requestWindow = null;
+
+		drawEvents();
+	}
+
+	/**
+	 * Resets the timeband and redraws it
+	 */
+	public void redrawEmptyBand() {
+		events.clear();
+		redrawBand();
+	}
+
+	/**
+	 * true if the band is targetted from user input
+	 * 
+	 * @param isUserInterested identifies whether a user is interested in the
+	 *            band
+	 */
+	public void registerUserInterest(final boolean isUserInterested) {
+		this.isUserInterested = isUserInterested;
+	}
+
+	/**
+	 * Removes an event from the band
+	 * 
+	 * @param id the id of the event to be removed.
+	 * @throws CannotDeleteEventException An event cannot be removed from a
+	 *             timeband.
+	 */
+	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
+	}
+
+	/**
+	 * resets the band to use the original unit
+	 */
+	public void resetOriginalUnit() {
+		setUnit(originalUnit);
+	}
+
+	/**
+	 * Resizes bands dependant on how many bands are present.
+	 */
+	public void resizeBand() {
+		if (isUserInterested) {
+			// resize the timeband to take account of the number of timetracks
+			new El(timebandContainer).setHeight(tapeTracks.size() * TimelineConstants.TAPE_TRACK_HEIGHT);
+		}
+	}
+
+	/**
+	 * Gets the band to scroll to the current date
+	 */
+	public void scrollToCurrentDate() {
+		Log.debug("Client width /2 : " + (timebandContainer.getClientWidth() / 2));
+		new El(timebandContainer)
+				.setScrollLeft((int) currentDateX - (timebandContainer.getClientWidth() / 2));
+		displayTimebandLabel();
+	}
+
+	/**
+	 * @param bandDiv the bandDiv to set
+	 */
+	public final void setBandDiv(final Element bandDiv) {
+		this.bandDiv = bandDiv;
+	}
+
+	/**
+	 * resetting the current date...
+	 * 
+	 * @param currentDate the date on which the timeband is rooted
+	 */
+	public void setCurrentDate(final long currentDate) {
+		this.currentDate = currentDate;
+
+		// if we're changing the date, then everything on the band is going to
+		// be wrong, so
+		// get rid of it...
+
+	}
+
+	/**
+	 * @param currentDateX the currentDateX to set
+	 */
+	public void setCurrentDateX(final long currentDateX) {
+		this.currentDateX = currentDateX;
+	}
+
+	/**
+	 * @param deletionsDisabled the deletionsDisabled to set
+	 */
+	public void setDeletionsDisabled(final boolean deletionsDisabled) {
+		this.deletionsDisabled = deletionsDisabled;
+	}
+
+	/**
+	 * @param description the description to set
+	 */
+	public void setDescription(final String description) {
+		this.description = description;
+	}
+
+	/**
+	 * @param id the id to set
+	 */
+	public void setId(final int id) {
+		this.id = id;
+	}
+
+	/**
+	 * @param maxDate the maxDate to set
+	 */
+	public void setMaxDate(final long maxDate) {
+		this.maxDate = maxDate;
+	}
+
+	/**
+	 * @param minDate the minDate to set
+	 */
+	public void setMinDate(final long minDate) {
+		this.minDate = minDate;
+	}
+
+	/**
+	 * Usuall, the first call ever to set the unit of the timeband. The original
+	 * unit gets cached in the originalUnit field For other uses, use @see
+	 * {@link Timeband.setUnit} If not set, then it gets set. Otherwise a
+	 * warning if produced
+	 * 
+	 * @param unit unit to be associated with the timeband
+	 */
+	public void setOriginalUnit(final Unit unit) {
+		if (originalUnit == null) {
+			originalUnit = unit;
+		} else {
+			Log.warn("Original unit is already set. Please use resetOriginalUnit instead");
+		}
+		resetOriginalUnit();
+	}
+
+	/**
+	 * @param outstandingUnitFactor the outstandingUnitFactor to set
+	 */
+	public void setOutstandingUnitFactor(final double outstandingUnitFactor) {
+		this.outstandingUnitFactor = outstandingUnitFactor;
+	}
+
+	/**
+	 * @param pixelsPerUnit the pixelsPerUnit to set
+	 */
+	public void setPixelsPerUnit(final int pixelsPerUnit) {
+		this.pixelsPerUnit = pixelsPerUnit;
+	}
+
+	/**
+	 * sets the new position of the window, when the user is moving it
+	 * 
+	 * @param previousClientX the previousPosition on the x axis
+	 * @param newClientX the new position where it should be moved
+	 * @param defaultUnit the default unit which should be used to calculate the
+	 *            time difference
+	 * @param defaultPixelsPerUnit the default number of pixels per unit
+	 */
+	public void setScrollLeft(final int previousClientX, final int newClientX, final Unit defaultUnit,
+			final 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
+		final 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
+		final double pixelFactor = (double) pixelsPerUnit / (double) defaultPixelsPerUnit;
+		final double xAxisDiff = (previousClientX - newClientX) * (unitFactor * pixelFactor);
+		final int newScrollLeft = (int) (mouseDownScrollLeft + xAxisDiff);
+		this.timebandContainer.setScrollLeft(newScrollLeft);
+		displayTimebandLabel();
+	}
+
+	/**
+	 * @param showScale the showScale to set
+	 */
+	public void setShowScale(final boolean showScale) {
+		this.showScale = showScale;
+	}
+
+	/**
+	 * @param unit the unit to set
+	 */
+	public void setUnit(final Unit unit) {
+		this.unit = unit;
+	}
+
+	/**
+	 * @param zoomFactor the zoomFactor to set
+	 */
+	public void setZoomFactor(final double zoomFactor) {
+		this.zoomFactor = zoomFactor;
+	}
+
+	/**
+	 * Zooms in
+	 */
+	public void zoomIn() {
+		zoom(1 + zoomFactor);
+	}
+
+	/**
+	 * 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);
+
+	}
+
+	/**
+	 * Adds an event to the tape track. This ensures that the event has not
+	 * already been rendered If so, then it is present somewhere, perhaps not on
+	 * this band though. Then, iterates through the tape tracks trying to add
+	 * the event (i.e. asking each track whether there is space for the icon and
+	 * the text to be added)
+	 * 
+	 * @param event event to be added to the tape track
+	 */
+	private void addEventToTapeTrack(final TimeEvent event) {
+		int startIndex = showScale ? 1 : 0; // leaving room for the scale band
+
+		// if event is added already, then exit
+		if (event.isRendered()) {
+			return;
+		}
+
+		while (startIndex < tapeTracks.size()) {
+			// Log.debug("Trying to add " + event.getDescription() +
+			// " to track " + startIndex);
+			// try and add event to track
+			if (tapeTracks.get(startIndex).addEvent(event)) {
+				return;
+			}
+			startIndex++;
+		}
+
+		// Log.debug("Going to create a new tape track");
+
+		// check that the event was added, otherwise add timetrack
+		if (startIndex >= tapeTracks.size()) {
+			// did not manage to add it to tracks. therefore, let's add another
+			// one:
+			final TapeTrack t = addNewTapeTrack();
+			t.addEvent(event);
+		}
+	}
+
+	/**
+	 * Adds the timeband label to the band
+	 */
+	private void addLabelToBand() {
+		timebandLabel = DOM.createDiv();
+		final El gxtTimebandLabel = new El(timebandLabel);
+		gxtTimebandLabel.setStyleName("step-timeband-label", true);
+		gxtTimebandLabel.setLeft(getElement().getScrollLeft());
+		timebandLabel.setInnerText(description + "(" + id + ")");
+		timebandContainer.appendChild(timebandLabel);
+
+	}
+
+	/**
+	 * adds a new tape track to the timeband. The TapeTrack gets rendered at the
+	 * same time
+	 * 
+	 * @return the TapeTrack that was added
+	 */
+	private TapeTrack addNewTapeTrack() {
+		final TapeTrack t = new TapeTrack();
+		tapeTracks.add(t);
+		t.paint(this);
+		return t;
+	}
+
+	/**
+	 * TODO: The idea is to adjust depending on how many pixels constitutes a
+	 * unit so that we can easily zoom in and out and have the units repainted
+	 * properly
+	 */
+	private void adjustUnit() {
+
+	}
+
+	/**
+	 * Displays the timeband label on the timeband, with the description of it
+	 */
+	private void displayTimebandLabel() {
+		new El(timebandLabel).setLeft(getElement().getScrollLeft());
+	}
+
+	/**
+	 * Draws event onto the band
+	 */
+	private void drawEvents() {
+		// get the events to paint themselves (they will decide whether or not
+		// to
+		// paint if they are already showing...
+		for (final TimeEvent te : events.values()) {
+			addEventToTapeTrack(te);
+		}
+	}
+
+	/**
+	 * 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(final TimeEvent event) {
+		final Long eventMinDate = event.getMinDate();
+		final Long eventMaxDate = event.getMaxDate(); // eventMaxDate can be
+		// null
+		final long minVisibleDate = getMinVisibleDate();
+		final 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;
+	}
+
+	/**
+	 * Resets the rendered status on all events
+	 */
+	private void resetAllEvents() {
+		for (final TimeEvent te : events.values()) {
+			te.reset();
+		}
+	}
+
+	/**
+	 * Zooms out given a ratio
+	 * 
+	 * @param zoomRatio the given ratio to zoom in and out
+	 */
+	private void zoom(final double zoomRatio) {
+		// TODO: somehow start with those events in the window (although for
+		// zoomout, won't make a different
+		// first change the scale
+		pixelsPerUnit *= zoomRatio;
+		adjustUnit();
+		redrawBand();
+	}
+
+	/**
+	 * adds the band to the DOM
+	 */
+	protected void addBandToUI() {
+		final El el = new El(timebandContainer);
+		final El gxtBandDiv = new El(bandDiv);
+
+		// set display options, ie. auto hide
+		// if (autoHide && !hasVisibleEvents()) {
+		// el.setDisplayed(false);
+		// }
+
+		parent.getTimelineContainer().appendChild(timebandContainer);
+		timebandContainer.appendChild(bandDiv);
+		addLabelToBand();
+
+		el.setStyleName("step-timeband-container");
+		gxtBandDiv.setHeight("100%");
+		gxtBandDiv.setTop(0);
+	}
+
+	/**
+	 * Repaints the timeband
+	 * 
+	 * @param top
+	 */
+	protected void paint() {
+		// Log.debug("Request to paint band id:" + getId() + " Current date: " +
+		// getCurrentDate() + " Desc:" + getDescription());
+		if (!isRendered) {
+			addBandToUI();
+			isRendered = true;
+		}
+
+		// show scale band?
+		if (showScale) {
+			// check if default time track has been added and add if not
+			if (tapeTracks.size() == 0) {
+				addNewTapeTrack();
+			}
+
+			if (timescale == null) {
+				timescale = new TimeScale(this);
+			}
+			timescale.paint();
+		}
+
+		drawEvents();
+
+		if (isUserInterested) {
+			// after adding events, call the resizing function.
+			// It decides whether or not the band needs resizing, so no overhead
+			resizeBand();
+		} else {
+			hideFromUser();
+		}
+	}
+}

Added: 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	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/Timeline.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,564 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline;
+
+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.dom.client.EventTarget;
+import com.google.gwt.event.dom.client.MouseDownEvent;
+import com.google.gwt.event.dom.client.MouseEvent;
+import com.google.gwt.event.dom.client.MouseMoveEvent;
+import com.google.gwt.event.dom.client.MouseOutEvent;
+import com.google.gwt.event.dom.client.MouseOverEvent;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+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.event.TimebandListUpdateRequiredEvent;
+import com.tyndalehouse.step.web.client.event.TimelineScrollEvent;
+import com.tyndalehouse.step.web.client.event.UserInterestInBandEvent;
+import com.tyndalehouse.step.web.client.eventhandler.UserInterestInBandEventHandler;
+import com.tyndalehouse.step.web.client.toolkit.timeline.components.TimelineConstants;
+import com.tyndalehouse.step.web.client.toolkit.timeline.events.TimelineMouseHandler;
+import com.tyndalehouse.step.web.client.toolkit.timeline.exceptions.IncapableOfCalculatingRequestWindowException;
+import com.tyndalehouse.step.web.client.toolkit.timeline.exceptions.TimeBandNotFoundException;
+import com.tyndalehouse.step.web.client.toolkit.timeline.exceptions.UnknownFiredElement;
+import com.tyndalehouse.step.web.client.toolkit.timeline.helpers.CurrentBandStats;
+import com.tyndalehouse.step.web.shared.common.timeline.TimeBandVisibleDate;
+import com.tyndalehouse.step.web.shared.timeline.Unit;
+
+/**
+ * FEATURE: Add uncertain times from database as dotted events/bands FEATURE:
+ * Add red line down the middle as current Sync line that tells user where bands
+ * are sunk FEATURE: Proper descriptions appearing in hover popups FEATURE: Add
+ * support for timetagging, history links, so that user can copy and paste url
+ * BUG: Fix obvious units that are wrong BUG: Timeline doesn't render properly
+ * when stuff is cached
+ * 
+ * 
+ * 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 {
+
+	/**
+	 * Client X records the last X-axis mouse position
+	 */
+	private int clientX;
+
+	/**
+	 * Map of hover over popups that describe an event
+	 */
+	private final TimeEventDescriptor descriptor;
+
+	/**
+	 * keeps track of whether the mouse button is up or down
+	 */
+	private boolean downStatus;
+
+	/**
+	 * The event bus on which to fire events
+	 */
+	private final EventBus eventBus;
+
+	/**
+	 * the current height of the timeline module
+	 */
+	private int height;
+
+	/**
+	 * whether the timeline is displayed horizontally or vertically (vertically
+	 * is not currently supported)
+	 */
+	private boolean isHorizontal;
+
+	/**
+	 * whether the timeline module has been rendered
+	 */
+	private boolean isRendered = false;
+
+	/**
+	 * The list of timebands
+	 */
+	private final List<Timeband> timebands;
+
+	/**
+	 * The container for the timeline module, a DOM element wrapping the whole
+	 * lot this is for styling and makes it easier
+	 */
+	private final Element timelineContainer;
+
+	/**
+	 * the timeline div, in which everything gets done.
+	 */
+	private final Element timelineDiv;
+
+	/**
+	 * The current width of the timeline module when rendered
+	 */
+	private int width;
+
+	/**
+	 * Default constructor
+	 * 
+	 * @param eventBus the event bus to fire events on
+	 */
+	public Timeline(final 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);
+
+		// set up hover over
+		descriptor = new TimeEventDescriptor(this);
+
+		paint();
+		addEventHandlers(eventBus);
+		disableSelection(getElement());
+	}
+
+	/**
+	 * Adds a band to a timeline module
+	 * 
+	 * @param band the timeband to be added
+	 */
+	public synchronized void addBand(final Timeband band) {
+		timebands.add(band);
+		band.paint();
+	}
+
+	/**
+	 * 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() {
+		final 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 (final 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
+
+				final TimeBandVisibleDate tvd = tb.getOustandingTimebandPeriod();
+				Log.debug("firing scroll " + tb.getDescription() + " " + tvd.getMinDate() + ","
+						+ tvd.getMaxDate());
+				tse.addTimebandVisibleDate(tvd);
+			} catch (final 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 {
+			// this is fired after the scroll has got the events,
+			// but in this case we're not event firing
+			// the event, so should update the stats, since the visible view has
+			// changed
+			eventBus.fireEvent(new TimebandListUpdateRequiredEvent(getCurrentBandStats()));
+		}
+	}
+
+	/**
+	 * returns a band to the caller based on the band id
+	 * 
+	 * @param bandId the band id of the band to be returned
+	 * @return the relevant timeband
+	 * @throws TimeBandNotFoundException thrown if bandId is not part of this
+	 *             timeline module
+	 */
+	public Timeband getBand(final int bandId) throws TimeBandNotFoundException {
+		// do a linear search - we're not going to have lots of timebands
+		for (final Timeband t : timebands) {
+			if (t.getId() == bandId) {
+				return t;
+			}
+		}
+
+		throw new TimeBandNotFoundException("Timeband " + bandId + " was not found.");
+	}
+
+	/**
+	 * Returns the number of bands to the caller
+	 * 
+	 * @return the number of bands on the timeline module
+	 */
+	public int getBandCount() {
+		return timebands.size();
+	}
+
+	/**
+	 * returns the list of the timeband. This is rather dangerous, and probably
+	 * should be protected
+	 * 
+	 * @return the list of timebands
+	 */
+	public List<Timeband> getBands() {
+		return timebands;
+	}
+
+	/**
+	 * returns the stats for all timebands to the caller
+	 * 
+	 * @return a list containing lots of @see {@link CurrentBandStats}
+	 */
+	public List<CurrentBandStats> getCurrentBandStats() {
+		final List<CurrentBandStats> stats = new ArrayList<CurrentBandStats>();
+		for (final Timeband band : timebands) {
+
+			final CurrentBandStats bandStats = new CurrentBandStats(band.getId(), band.getDescription(), band
+					.getEvents().size(), band.getNumberOfVisibleEvents(), band.isUserInterested());
+			stats.add(bandStats);
+		}
+
+		return stats;
+	}
+
+	/**
+	 * @return the height
+	 */
+	public int getHeight() {
+		return height;
+	}
+
+	/**
+	 * @return the timelineContainer
+	 */
+	public Element getTimelineContainer() {
+		return timelineContainer;
+	}
+
+	/**
+	 * @return the width
+	 */
+	public int getWidth() {
+		return width;
+	}
+
+	/**
+	 * handles the mouse event, by alerting all the various bands to capture the
+	 * position of the mouse on them
+	 * 
+	 * @param e mouse event
+	 */
+	public void handle(final MouseDownEvent e) {
+		downStatus = true;
+		clientX = e.getClientX();
+
+		// capture scrollLeft on every timeband
+		for (final Timeband tb : timebands) {
+			tb.captureScrollLeft(e);
+		}
+
+		// Log.debug("ClientX " + clientX);
+
+		// change cursor to hand grab
+		new El(timelineDiv).setStyleName("step-grab", true);
+
+		// cursor: hand; /* ? */ TODO
+	}
+
+	/**
+	 * handles a move of the mouse, Ensures we know what timeband has been fired
+	 * then if the mouse is down, then tells timebands to move across else,
+	 * perhaps we're mouse hovering over something, and a popup needs to be
+	 * shown
+	 * 
+	 * @param e the mouse move event
+	 */
+	public void handle(final MouseMoveEvent e) {
+		if (timebands.size() != 0) {
+			Timeband firedBand;
+			try {
+				firedBand = getFiredBand(e);
+			} catch (final UnknownFiredElement e1) {
+				Log.warn("Unknown element was fired");
+				firedBand = timebands.get(0);
+			}
+
+			final Unit unit = firedBand.getUnit();
+			final int pixelsPerUnit = firedBand.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
+				// 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 (final Timeband tb : timebands) {
+					tb.setScrollLeft(clientX, e.getClientX(), unit, pixelsPerUnit);
+					// Log.debug("About to scroll: " + (clientX -
+					// e.getClientX()));
+				}
+
+				// 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();
+			} else {
+				handleMouseOverTimeEvent(e);
+			}
+		}
+		// ignore if no timebands, as it is not fully rendered
+	}
+
+	/**
+	 * Sets the down status to false, simulating a mouse up, recording whether
+	 * the mouse is up or down, to false
+	 * 
+	 * @param event mouse out event
+	 */
+	public void handle(final MouseOutEvent event) {
+		downStatus = false;
+	}
+
+	/**
+	 * on mouse over event, we call handleMouseOverTimeEvent to work out which
+	 * TimeEvent fired the event if at all
+	 * 
+	 * @param e mouse over event
+	 */
+	public void handle(final MouseOverEvent e) {
+		handleMouseOverTimeEvent(e);
+	}
+
+	/**
+	 * on mouse up, we set the down status to false, and update the mouse icon
+	 * 
+	 * @param e mouse up event
+	 */
+	public void handle(final MouseUpEvent e) {
+		downStatus = false;
+		new El(timelineDiv).setStyleName("step-letgo", true);
+	}
+
+	/**
+	 * handles the display or remove of the popup An awful lot of events are
+	 * going to fired and captured and discarded and one wonders if this is
+	 * really the best way to do it
+	 * 
+	 * @param e move over event
+	 */
+	public void handleMouseOverTimeEvent(final MouseEvent<?> e) {
+		final EventTarget et = e.getNativeEvent().getEventTarget();
+		final Element targetElement = et.cast();
+
+		// find out if moved over event:
+		// Log.debug("Scanning " + timebands.size() + " timebands");
+		for (final Timeband band : timebands) {
+			// Log.debug("Scanning " + band.getEvents().size());
+			for (final TimeEvent te : band.getEvents().values()) {
+				if (te.getEventDiv().isOrHasChild(targetElement)) {
+					// Log.debug("Found event:" + te.getId() + " " +
+					// te.getDescription());
+					this.descriptor.show(te, e);
+					return;
+				}
+			}
+		}
+
+		// if no events found, then hide description:
+		this.descriptor.hide();
+	}
+
+	/**
+	 * @return the isHorizontal
+	 */
+	public boolean isHorizontal() {
+		return isHorizontal;
+	}
+
+	/**
+	 * call this when you want to force a repaint
+	 */
+	public synchronized void paint() {
+		if (!isRendered) {
+			timelineDiv.appendChild(timelineContainer);
+
+			int relativeTop = 0;
+			for (final Timeband tb : timebands) {
+				tb.paint();
+				relativeTop += tb.getSizeTapeTracks() * TimelineConstants.TAPE_TRACK_HEIGHT;
+			}
+
+			// the total relative at this stage is the total height of the
+			// timeline
+			new El(timelineDiv).setHeight(relativeTop);
+			isRendered = true;
+		}
+	}
+
+	/**
+	 * Repaints a particular timeband
+	 * 
+	 * @param originDate date at which to start
+	 * @param unit unit to be used on the timeband
+	 * @param timebandId the timeband id
+	 */
+	public void repaint(final Long originDate, final Unit unit, final int timebandId) {
+		// remove all the timebands from the timeline widget
+		// TODO: HERE all we want to do is set the corect timeband with that
+		// unit, not all of them, right?
+		// what if we have several timebands in the origin, is that possible?
+		// events on different timebands with the same scripture references
+
+		// TODO: set other timbands back to their original scales
+
+		for (final Timeband band : timebands) {
+			setUserInterestOnBand(band, timebandId, unit);
+			band.setCurrentDate(originDate);
+			band.setCurrentDateX(TimelineConstants.TIMELINE_WIDTH + timelineDiv.getClientWidth() / 2);
+			band.scrollToCurrentDate();
+			band.redrawEmptyBand();
+		}
+
+		fireTimelineScrollEvent();
+	}
+
+	/**
+	 * @param height the height to set
+	 */
+	public void setHeight(final int height) {
+		this.height = height;
+	}
+
+	/**
+	 * @param isHorizontal the isHorizontal to set
+	 */
+	public void setHorizontal(final boolean isHorizontal) {
+		this.isHorizontal = isHorizontal;
+	}
+
+	/**
+	 * @param width the width to set
+	 */
+	public void setWidth(final int width) {
+		this.width = width;
+	}
+
+	/**
+	 * Zooming is done on a band level, so delegate to timebands
+	 */
+	public void zoomIn() {
+		for (final Timeband tb : timebands) {
+			tb.zoomIn();
+		}
+	}
+
+	/**
+	 * Zooming is done on a band level, so delegate to timebands
+	 */
+	public void zoomOut() {
+		for (final Timeband tb : timebands) {
+			tb.zoomOut();
+		}
+	}
+
+	/**
+	 * adds event handlers to capture mouse movements, clicks, etc
+	 * 
+	 * @param eventBus event bus on which to register some handlers
+	 */
+	// TODO: investigate pushing the handlers in to the handler!!!
+	private void addEventHandlers(final EventBus eventBus) {
+		final TimelineMouseHandler tmh = new TimelineMouseHandler(this);
+		addDomHandler(tmh, MouseMoveEvent.getType());
+		addDomHandler(tmh, MouseUpEvent.getType());
+		addDomHandler(tmh, MouseDownEvent.getType());
+		addDomHandler(tmh, MouseOutEvent.getType());
+		addDomHandler(tmh, MouseOverEvent.getType());
+
+		eventBus.addHandler(UserInterestInBandEvent.TYPE, new UserInterestInBandEventHandler() {
+
+			public void onUserInterestedInBand(final UserInterestInBandEvent userInterestInBandEvent) {
+				try {
+					final Timeband band = getBand(userInterestInBandEvent.getBandId());
+					band.registerUserInterest(userInterestInBandEvent.isOfInterest());
+					band.paint();
+				} catch (final TimeBandNotFoundException e) {
+					Log.warn("The user request a band that no longer exists.");
+				}
+			}
+		});
+
+		// TODO: add window handler
+
+	}
+
+	/**
+	 * Disables the user selection on the timeline widget, to ensure the user
+	 * gets a good experience
+	 * 
+	 * @param e the DOM element on which to perform these javascript operations
+	 */
+	private native void disableSelection(final Element e) /*-{
+		e.ondrag = function() { return false; };
+		e.onselectstart = function() { return false; };
+		e.style.MozUserSelect = "none";
+	}-*/;
+
+	/**
+	 * returns the fired timeband band, given a mouse move event
+	 * 
+	 * @param e the mouse band
+	 * @return the timeband that was fired
+	 * @throws UnknownFiredElement thrown if we do not know which timeband was
+	 *             fired
+	 */
+	private Timeband getFiredBand(final MouseMoveEvent e) throws UnknownFiredElement {
+		final EventTarget et = e.getNativeEvent().getEventTarget();
+		final Element targetElement = et.cast();
+
+		for (final Timeband b : timebands) {
+			if (b.getBandDiv().isOrHasChild(targetElement)) {
+				return b;
+			}
+		}
+
+		throw new UnknownFiredElement();
+	}
+
+	/**
+	 * if the band corresponds to the correct timeband id, then set unit,
+	 * otherwise revert back to the original state...
+	 * 
+	 * @param band band
+	 * @param timebandId timebandId
+	 * @param unit unit
+	 */
+	private void setUserInterestOnBand(final Timeband band, final int timebandId, final Unit unit) {
+		if (band.getId() == timebandId) {
+			band.setUnit(unit);
+			band.registerUserInterest(true);
+		} else {
+			band.resetOriginalUnit();
+			band.registerUserInterest(false);
+		}
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/Orientation.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/Orientation.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/Orientation.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,21 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.components;
+
+/**
+ * This determines whether to render the timeband horizontally or vertically. At
+ * the moment only HORIZONTAL is supported.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public enum Orientation {
+	/**
+	 * Render the timeband horizontally
+	 */
+	HORIZONTAL,
+
+	/**
+	 * Render the timeband vertically
+	 */
+	VERTICAL,
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/TimebandRequestWindow.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/TimebandRequestWindow.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/TimebandRequestWindow.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,82 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.components;
+
+/**
+ * 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 {
+	/** max date requested so far */
+	private long maxDate;
+
+	/** min date requested so far */
+	private long minDate;
+
+	/**
+	 * timeband request window, when created takes the intial window (min, max)
+	 * 
+	 * @param initialMin initial minimum, usually the left most visible pixel of
+	 *            the timeband
+	 * @param initialMax initial maximum, usually the right most visible pixel
+	 *            of the timeband
+	 */
+	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
+	 * @param maxDateRequested the new maxDate that the band has received
+	 */
+	public void adjustRange(final long minDateRequested, final 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 maxDate
+	 */
+	public long getMaxDate() {
+		return maxDate;
+	}
+
+	/**
+	 * @return the minDate
+	 */
+	public long getMinDate() {
+		return minDate;
+	}
+
+	/**
+	 * @param maxDate the maxDate to set
+	 */
+	public void setMaxDate(final long maxDate) {
+		this.maxDate = maxDate;
+	}
+
+	/**
+	 * @param minDate the minDate to set
+	 */
+	public void setMinDate(final long minDate) {
+		this.minDate = minDate;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/TimelineConstants.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/TimelineConstants.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/components/TimelineConstants.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,85 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.components;
+
+/**
+ * Timeline constants to be used in the timeline module
+ * 
+ * @author CJBurrell
+ * 
+ */
+public final class TimelineConstants {
+
+	/**
+	 * This is the setting defining how many pixels represent 1 unit
+	 */
+	public static final int DEFAULT_PIXELS_PER_UNIT = 100;
+	/**
+	 * for a duration event, the css class
+	 */
+	public static final String DURATION = "step-timeline-duration";
+	/**
+	 * css class for a label of a duration event
+	 */
+	public static final String DURATION_LABEL = "step-time-duration-label";
+	/**
+	 * step time event css
+	 */
+	public static final String EVENT = "step-time-event";
+	/**
+	 * the minimum width of an event
+	 */
+	public static final int EVENT_MIN_WIDTH = 2;
+
+	/**
+	 * The initial date for the timeline, the date of birth of Jesus
+	 */
+	public static final long INITIAL_DATE = -61183987174853L;
+	/**
+	 * this describes how much of a unit needs to be visible before calling back
+	 * to the server
+	 */
+	public static final double MINIMUM_UNIT_PORTION_BEFORE_SERVER_CALL = 0.5;
+	/**
+	 * css of a point in time event
+	 */
+	public static final String POINT_IN_TIME_EVENT = "step-timeline-pointInTime";
+
+	/**
+	 * css for the label of a point in time event label
+	 */
+	public static final String POINT_IN_TIME_LABEL = "step-time-point-in-time-label";
+
+	/**
+	 * space between the icon and the text
+	 */
+	public static final int POINT_IN_TIME_WIDTH_SPACE = 15;
+
+	/**
+	 * space between the popup and the mouse
+	 */
+	public static final int SPACE_BELOW_POPUP = 20;
+
+	/**
+	 * height of each tape track
+	 * 
+	 */
+	public static final int TAPE_TRACK_HEIGHT = 21;
+
+	/**
+	 * total width of timeline width, hardcoded at the moment
+	 */
+	// TODO: parameterize this depending on the length of the band
+	public static final int TIMELINE_WIDTH = 32000;
+
+	/**
+	 * The initial zoom factor. 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
+	 */
+	public static final double ZOOM_FACTOR = 0.25;
+
+	/**
+	 * prevent intialisation
+	 */
+	private TimelineConstants() {
+	}
+}

Added: 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/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	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,58 @@
+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.MouseOverEvent;
+import com.google.gwt.event.dom.client.MouseOverHandler;
+import com.google.gwt.event.dom.client.MouseUpEvent;
+import com.google.gwt.event.dom.client.MouseUpHandler;
+import com.tyndalehouse.step.web.client.toolkit.timeline.Timeline;
+
+/**
+ * timeline mouse handler to re-delegate events to the timeline component this
+ * is used mainly for the scrolling functionality on the timeline
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimelineMouseHandler implements MouseMoveHandler, MouseUpHandler, MouseDownHandler,
+		MouseOutHandler, MouseOverHandler {
+	/**
+	 * The timeline component
+	 */
+	private final Timeline timeline;
+
+	/**
+	 * constructor takes the timeline component
+	 * 
+	 * @param timeline the timeline component.
+	 */
+	public TimelineMouseHandler(final Timeline timeline) {
+		this.timeline = timeline;
+	}
+
+	public void onMouseDown(final MouseDownEvent event) {
+		timeline.handle(event);
+	}
+
+	public void onMouseMove(final MouseMoveEvent event) {
+		timeline.handle(event);
+	}
+
+	public void onMouseOut(final MouseOutEvent event) {
+		timeline.handle(event);
+	}
+
+	public void onMouseOver(final MouseOverEvent event) {
+		timeline.handle(event);
+
+	}
+
+	public void onMouseUp(final MouseUpEvent event) {
+		timeline.handle(event);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/CannotDeleteEventException.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/CannotDeleteEventException.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/CannotDeleteEventException.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,27 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.exceptions;
+
+/**
+ * The request to delete an event has failed. The message should explain why
+ * this has happened.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class CannotDeleteEventException extends Exception {
+
+	/**
+	 * The default constructor with the explanatory message
+	 * 
+	 * @param message
+	 *            The message for the exception
+	 */
+	public CannotDeleteEventException(final String message) {
+		super(message);
+	}
+
+	/**
+	 * Serialisation id
+	 */
+	private static final long serialVersionUID = -9221252482310063155L;
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/IncapableOfCalculatingRequestWindowException.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/IncapableOfCalculatingRequestWindowException.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/IncapableOfCalculatingRequestWindowException.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,32 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.exceptions;
+
+/**
+ * The request window is the window of pixels (start/end) that gets send to the
+ * server indicating the client wants to get events that are in that time
+ * section There are certain situations where it is impossible to calculate how
+ * the user has moved, for example when the browser moves so quickly that the
+ * whole screen shifts 1 screen-wide of pixels
+ * 
+ * @author CJBurrell
+ */
+public class IncapableOfCalculatingRequestWindowException extends Exception {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 1866493907904681758L;
+
+	/**
+	 * The client is unable to calculate which bit to request from the server
+	 * 
+	 * @param minVisibleDate the minimum visible date from the client
+	 * @param maxVisibleDate the maximum visible date from the client
+	 * @param minReceivedDate the minimum date the client has ever seen
+	 * @param maxReceivedDate the maximum date the client has ever seen
+	 */
+	public IncapableOfCalculatingRequestWindowException(final long minVisibleDate, final long maxVisibleDate,
+			final long minReceivedDate, final long maxReceivedDate) {
+		super("Unable to calculate request window for: " + minReceivedDate + " / " + maxReceivedDate
+				+ ". Visible section is: " + minVisibleDate + " / " + maxVisibleDate);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/TimeBandNotFoundException.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/TimeBandNotFoundException.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/TimeBandNotFoundException.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,25 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.exceptions;
+
+/**
+ * While trying to lookup the timeband, it was not found
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimeBandNotFoundException extends Exception {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 6234571991235670035L;
+
+	/**
+	 * Constructor specifying the error message
+	 * 
+	 * @param message message indicating which band was not found
+	 */
+	public TimeBandNotFoundException(final String message) {
+		super(message);
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/UnknownFiredElement.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/UnknownFiredElement.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/exceptions/UnknownFiredElement.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,17 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.exceptions;
+
+/**
+ * Thrown if an DOM element contained in the timeline is fired but it is not
+ * recognised by the timeline element
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class UnknownFiredElement extends Exception {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -726869406002130223L;
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/CurrentBandStats.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/CurrentBandStats.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/CurrentBandStats.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,87 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.helpers;
+
+/**
+ * Contains the current statistics of how many events are present on a
+ * particular timeband This bean is band specific
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class CurrentBandStats {
+	/**
+	 * description of the band to be displayed on the screen
+	 */
+	private final String bandDescription;
+
+	/**
+	 * timeband id
+	 */
+	private final int bandId;
+
+	/**
+	 * ticked or not, whether the user is interested in this
+	 */
+	private final boolean isUserInterested;
+
+	/**
+	 * number of elements on the timeband
+	 */
+	private final int numElements;
+
+	/**
+	 * number of elements currently visible
+	 */
+	private final int numVisibleElements;
+
+	/**
+	 * 
+	 * @param bandId the id of the band
+	 * @param numElements the number of events on the band
+	 * @param numVisibleElements the number of visible events in the frame
+	 * @param bandDescription description to be displayed on the view
+	 * @param isUserInterested whether the user is interested in the band
+	 */
+	public CurrentBandStats(final int bandId, final String bandDescription, final int numElements,
+			final int numVisibleElements, final boolean isUserInterested) {
+		this.bandId = bandId;
+		this.bandDescription = bandDescription;
+		this.numElements = numElements;
+		this.numVisibleElements = numVisibleElements;
+		this.isUserInterested = isUserInterested;
+	}
+
+	/**
+	 * @return the bandDescription
+	 */
+	public String getBandDescription() {
+		return bandDescription;
+	}
+
+	/**
+	 * @return the bandId
+	 */
+	public int getBandId() {
+		return bandId;
+	}
+
+	/**
+	 * @return the numElements
+	 */
+	public int getNumElements() {
+		return numElements;
+	}
+
+	/**
+	 * @return the numVisibleElements
+	 */
+	public int getNumVisibleElements() {
+		return numVisibleElements;
+	}
+
+	/**
+	 * @return the isUserInterested
+	 */
+	public boolean isUserInterested() {
+		return isUserInterested;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/TimeConversionUtil.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/TimeConversionUtil.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/toolkit/timeline/helpers/TimeConversionUtil.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,92 @@
+package com.tyndalehouse.step.web.client.toolkit.timeline.helpers;
+
+import java.util.Date;
+
+import com.google.gwt.i18n.client.DateTimeFormat;
+import com.tyndalehouse.step.web.client.toolkit.timeline.Timeband;
+import com.tyndalehouse.step.web.shared.timeline.Unit;
+
+/**
+ * Util class to convert time to date and vice versa
+ * 
+ * @author CJBurrell
+ * 
+ */
+public final class TimeConversionUtil {
+	/**
+	 * converts a pixel position to its date using the format associated to the
+	 * unit of the timeband
+	 * 
+	 * @param pixelPosition pixel position to be converted
+	 * @param timeband current timeband (this contains the current viewing
+	 *            location, and unit
+	 * @return the date as a formatted string
+	 */
+	public static String formatPixelToTime(final long pixelPosition, final Timeband timeband) {
+		return formatTime(pixelToTime(pixelPosition, timeband), timeband);
+	}
+
+	/**
+	 * formats the given time using the unit described in the timeband
+	 * 
+	 * @param timeband the timeband containing the current view, unit, etc.
+	 * @param eventDate date to be formatted
+	 * @return the string representation of the date
+	 */
+	public static String formatTime(final long eventDate, final Timeband timeband) {
+		final Date date = new Date(eventDate);
+		final String formatForBand = timeband.getUnit().getFormat();
+		final DateTimeFormat format = DateTimeFormat.getFormat(formatForBand);
+		return format.format(date);
+	}
+
+	/**
+	 * This takes a pixel position and returns the equivalent time
+	 * 
+	 * @param pixelPosition the pixel position that we are trying to convert
+	 * @param timeband the timeband which contains the relevant information
+	 *            (current view, unit) to calculate the time from the pixel
+	 *            position
+	 * @return the time of pixelPosition
+	 */
+	public static long pixelToTime(final long pixelPosition, final Timeband timeband) {
+		final long currentDateX = timeband.getCurrentDateX();
+		final long currentDate = timeband.getCurrentDate();
+		final Unit unit = timeband.getUnit();
+		final long pixelsPerUnit = timeband.getPixelsPerUnit();
+
+		final long differenceWithOrigin = pixelPosition - currentDateX;
+		final 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 currentTimeband reference timeband (including current view, unit,
+	 *            etc).
+	 * @return the pixel position on the timeband for the passed in time
+	 */
+	public static int timeToPixel(final long eventDate, final Timeband currentTimeband) {
+		// here's what we start from
+		final long millisecondPerUnit = currentTimeband.getUnit().getMilliseconds();
+		final long pixelsPerUnit = currentTimeband.getPixelsPerUnit();
+		final long currentOriginDate = currentTimeband.getCurrentDate();
+		final long currentOriginXPixel = currentTimeband.getCurrentDateX();
+
+		// what's one pixel in milliseconds?
+		final double onePixelInMs = (double) millisecondPerUnit / pixelsPerUnit;
+
+		// calculate difference with current position on timeband
+		final long differenceWithEvent = eventDate - currentOriginDate;
+		final long pixelValueOnBand = currentOriginXPixel + (long) (differenceWithEvent / onePixelInMs);
+		return (int) pixelValueOnBand;
+	}
+
+	/**
+	 * making the constructor invisible to outsiders
+	 */
+	private TimeConversionUtil() {
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/HistoryModuleView.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/HistoryModuleView.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/HistoryModuleView.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,87 @@
+package com.tyndalehouse.step.web.client.view;
+
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.tyndalehouse.step.web.client.presenter.HistoryModulePresenter;
+import com.tyndalehouse.step.web.client.toolkit.HtmlList;
+import com.tyndalehouse.step.web.client.toolkit.HtmlList.ListType;
+
+/**
+ * The history module TODO: revamp this completely
+ * 
+ * @author cjburrell
+ * 
+ */
+public class HistoryModuleView extends Composite implements HistoryModulePresenter.Display {
+
+	/**
+	 * an article
+	 */
+	private final HTML article;
+
+	/**
+	 * A contents page to choose from
+	 */
+	private final HtmlList contentsTable;
+
+	/**
+	 * default constructor
+	 */
+	public HistoryModuleView() {
+		final VerticalPanel vp = new VerticalPanel();
+		initWidget(vp);
+		article = new HTML();
+
+		article.setHTML("Abija Aviyam: \"Father of the sea\" or \"my father "
+				+ "is the sea\" or \"my father is Yah\") was the fourth king "
+				+ "of the House of David and the second of the Kingdom of "
+				+ "Judah. He was the son of Rehoboam, the grandson of Solomon "
+				+ "and the great-grandson of David. The Chronicler refers to "
+				+ "him as \"Abijah (Hebrew, \"my father is The LORD\"). "
+				+ "William F. Albright has dated his reign to 915 BC - 913 "
+				+ "BC, while E. R. Thiele offers the dates 914/913 - 911/910 BC. "
+				+ "[1] As explained in the Rehoboam article, Thiele's chronology for "
+				+ "the first kings of Judah contained an internal inconsistency "
+				+ "that later scholars corrected by dating these kings "
+				+ "one year earlier, so that Abijah's dates are taken as 915/914 "
+				+ "to 912/911 BC in the present article. The Hebrew Bible gives "
+				+ "his reign length as three years. His mother's name was Maacah, "
+				+ "or Micaiah, the granddaughter of the infamous Abishalom (Absalom). "
+				+ "Abijah married fourteen wives, and had 22 sons and 16 daughters. " + "[2]");
+
+		// contents at the top
+		contentsTable = new HtmlList(ListType.UNORDERED);
+		contentsTable.addItem("Abijah, Yah is my father", null);
+		contentsTable.addItem("Abijam, father of the sea", null);
+		contentsTable.addItem("Abilene, the father of mourning", null);
+
+		vp.add(contentsTable);
+		vp.add(article);
+	}
+
+	public Widget asWidget() {
+		return this;
+	}
+
+	/**
+	 * Sets the current article
+	 * 
+	 * @param articleText the text of the article to be viewed
+	 */
+	public void setArticle(final String articleText) {
+		article.setHTML(articleText);
+	}
+
+	public void startProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void stopProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ModuleSelectorView.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ModuleSelectorView.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ModuleSelectorView.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,133 @@
+package com.tyndalehouse.step.web.client.view;
+
+import java.util.List;
+
+import com.google.gwt.event.dom.client.HasChangeHandlers;
+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.tyndalehouse.step.web.client.presenter.ModuleSelectorPresenter;
+import com.tyndalehouse.step.web.client.toolkit.HasSource;
+import com.tyndalehouse.step.web.client.toolkit.SimpleListBox;
+
+/**
+ * The module selector view, displaying three levels of study
+ * <p />
+ * The module: History, Geography, etc. <br />
+ * <p />
+ * The sub-module: Genealogies,
+ * <p />
+ * 
+ * The depth: the depth at which people want to study (scholarly, light etc.)
+ * 
+ * @author cjburrell
+ * 
+ */
+public class ModuleSelectorView extends Composite implements ModuleSelectorPresenter.Display {
+	/**
+	 * a list of modules
+	 */
+	private final SimpleListBox module;
+
+	/**
+	 * a list of depths
+	 */
+	private final SimpleListBox moduleDepth;
+
+	/**
+	 * a list of sub modules, correlated to the list of modules
+	 */
+	private final SimpleListBox subModule;
+
+	/**
+	 * The default constructor
+	 */
+	public ModuleSelectorView() {
+		final FlowPanel p = new FlowPanel();
+		initWidget(p);
+
+		module = new SimpleListBox();
+		moduleDepth = new SimpleListBox();
+		subModule = new SimpleListBox();
+
+		p.add(module);
+		p.add(moduleDepth);
+		p.add(subModule);
+	}
+
+	public String getSelectedModule() {
+		// check that the module has been populated already!
+		if (module.getItemCount() == 0) {
+			return null;
+		}
+		
+		return module.getValue(module.getSelectedIndex());
+	}
+	
+	public void setSelectedModule(final String value) {
+		// simple linear search
+		for (int ii = 0; ii < module.getItemCount(); ii++) {
+			if (value.equals(module.getValue(ii))) {
+				module.setSelectedIndex(ii);
+				return;
+			}
+		}	
+	}
+	
+	
+	public String getSelectedSubModule() {
+		if (subModule.getItemCount() == 0) {
+			return null;
+		}
+		return subModule.getValue(subModule.getSelectedIndex());
+	}
+	
+	public Widget asWidget() {
+		return this;
+	}
+
+	public HasChangeHandlers getModuleChangeHandlers() {
+		return module;
+	}
+
+	public HasChangeHandlers getModuleDepthChangeHandlers() {
+		return moduleDepth;
+	}
+
+	public HasSource<List<String>> getModuleDepthSource() {
+		return moduleDepth;
+	}
+
+	public HasSource<List<String>> getModuleSource() {
+		return module;
+	}
+
+	public String getSelectedDepth() {
+		if (moduleDepth.getItemCount() == 0) {
+			return null;
+		}
+		return moduleDepth.getValue(moduleDepth.getSelectedIndex());
+	}
+
+
+
+	public HasChangeHandlers getSubModuleChangeHandlers() {
+		return subModule;
+	}
+
+	public HasSource<List<String>> getSubModuleSource() {
+		return subModule;
+	}
+
+
+	public void startProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void stopProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ScriptureSelectorView.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ScriptureSelectorView.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ScriptureSelectorView.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,95 @@
+package com.tyndalehouse.step.web.client.view;
+
+import java.util.Collection;
+
+import com.allen_sauer.gwt.log.client.Log;
+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.HasValue;
+import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
+import com.google.gwt.user.client.ui.SuggestBox;
+import com.google.gwt.user.client.ui.Widget;
+import com.tyndalehouse.step.web.client.presenter.ScriptureSelectorPresenter;
+
+/**
+ * This view provides the user with a way to select a portion of scripture. It
+ * therefore contains a textbox and a button to fire the event. The textbox is
+ * an auto-complete textbox
+ * 
+ * @author cjburrell
+ */
+public class ScriptureSelectorView extends Composite implements ScriptureSelectorPresenter.Display {
+	/**
+	 * the source of the auto comlete textbox
+	 */
+	private final MultiWordSuggestOracle oracle;
+
+	/**
+	 * the auto complete text box
+	 */
+	private final SuggestBox reference;
+
+	/**
+	 * the button fired to search
+	 */
+	private final Button search;
+
+	/**
+	 * the default constructor to render the view
+	 */
+	public ScriptureSelectorView() {
+		final FlowPanel p = new FlowPanel();
+		initWidget(p);
+
+		oracle = new MultiWordSuggestOracle();
+		reference = new SuggestBox(oracle);
+		p.add(reference);
+
+		// TODO: localise this
+		search = new Button("Lookup");
+		p.add(search);
+
+		Log.debug("== Scripture Selector View initialiased");
+	}
+
+	public void addSuggestion(final String suggestion) {
+		oracle.add(suggestion);
+	}
+
+	public void addSuggestions(final Collection<String> suggestions) {
+		oracle.addAll(suggestions);
+
+	}
+
+	public Widget asWidget() {
+		return this;
+	}
+
+	/**
+	 * @return the unvalidated biblical reference that is currently in the
+	 *         textbox
+	 */
+	public HasValue<String> getReference() {
+		return reference;
+	}
+
+	/**
+	 * @return the search button on which to append listeners
+	 */
+	public HasClickHandlers getSearch() {
+		return search;
+	}
+
+	public void startProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void stopProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ScriptureView.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ScriptureView.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/ScriptureView.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,207 @@
+package com.tyndalehouse.step.web.client.view;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+
+import net.customware.gwt.presenter.client.EventBus;
+
+import com.google.gwt.event.dom.client.HasChangeHandlers;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.InlineLabel;
+import com.google.gwt.user.client.ui.Panel;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.client.presenter.ScripturePresenter;
+import com.tyndalehouse.step.web.client.toolkit.HasSource;
+import com.tyndalehouse.step.web.client.toolkit.SourceListBox;
+import com.tyndalehouse.step.web.client.toolkit.scripture.ScriptureDisplayConstants;
+import com.tyndalehouse.step.web.client.toolkit.scripture.VerseLabel;
+import com.tyndalehouse.step.web.shared.scripture.Passage;
+import com.tyndalehouse.step.web.shared.scripture.TextualElement;
+import com.tyndalehouse.step.web.shared.scripture.Title;
+import com.tyndalehouse.step.web.shared.scripture.Verse;
+import com.tyndalehouse.step.web.shared.scripture.VerseContent;
+import com.tyndalehouse.step.web.shared.scripture.Word;
+
+/**
+ * This view aims to show Scripture to the user. In order to do this, the user
+ * can select a version from a dropdown. The
+ * 
+ * TODO: remove the eventBus from the view.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class ScriptureView extends Composite implements ScripturePresenter.Display {
+
+	/**
+	 * the auto list of bible versions
+	 */
+	private final SourceListBox bibleVersions;
+
+	// TODO: to be removed into the presenter
+	/**
+	 * the default event bus
+	 */
+	private final EventBus eventBus;
+
+	/**
+	 * a list of VerseLabel (wrappers of bible text) that are currently being
+	 * displayed and contain lemmas
+	 */
+	private final List<VerseLabel> lemmaWords;
+
+	/**
+	 * a list of VerseLabel (wrappers of bible text) that are currently being
+	 * displayed and contain morphs
+	 */
+	private final List<VerseLabel> morphs;
+
+	/**
+	 * a logical display of scripture, in that events can be attached to each of
+	 * the elements on this panel
+	 */
+	private final Panel scriptureHolder;
+
+	/**
+	 * a simple display of scripture as text
+	 */
+	private final HTML scriptureHTML;
+
+	/**
+	 * The default constructor
+	 * 
+	 * @param eventBus eventBus - //TODO: remove this
+	 */
+	@Inject
+	public ScriptureView(final EventBus eventBus) {
+		this.eventBus = eventBus;
+		final VerticalPanel vp = new VerticalPanel();
+		scriptureHolder = new FlowPanel();
+		lemmaWords = new ArrayList<VerseLabel>();
+		morphs = new ArrayList<VerseLabel>();
+
+		initWidget(vp);
+
+		bibleVersions = new SourceListBox();
+		bibleVersions.setStylePrimaryName("bibleVersionsDropDown");
+
+		// adding the dropdown with the bible versions
+		vp.add(bibleVersions);
+
+		// adding the html display of scripture
+		// TODO : Localise this here.
+		scriptureHTML = new HTML("Please lookup a reference");
+		vp.add(scriptureHTML);
+		vp.add(scriptureHolder);
+	}
+
+	public Widget asWidget() {
+		return this;
+	}
+
+	public HasChangeHandlers getChangeHandlers() {
+		return bibleVersions;
+	}
+
+	public String getSelectedBibleVersion() {
+		return bibleVersions.getValue(bibleVersions.getSelectedIndex());
+	}
+
+	public HasSource<SortedMap<String, String>> getSource() {
+		return bibleVersions;
+	}
+
+	public void highlight(final List<String> lemmaList) {
+		for (final VerseLabel vl : lemmaWords) {
+			for (final String l : lemmaList) {
+				if (vl.getLemma().contains(l)) {
+					vl.setStyleName(ScriptureDisplayConstants.EMPHASISE);
+				} else {
+					vl.removeStyleName(ScriptureDisplayConstants.EMPHASISE);
+				}
+			}
+		}
+	}
+
+	public void setPassage(final Passage passage) {
+		final List<VerseContent> verseContent = passage.getVerseContent();
+
+		// clear current text:
+		scriptureHolder.clear();
+
+		for (final VerseContent v : verseContent) {
+			if (v instanceof Title) {
+				doTitle((Title) v);
+			} else if (v instanceof Verse) {
+				doVerse((Verse) v);
+			}
+		}
+
+	}
+
+	// TODO: probably remove the following function, and ensure the service is
+	// removed at the same time
+	public void setPassage(final String text) {
+		scriptureHTML.setHTML(text);
+	}
+
+	public void startProcessing() {
+	}
+
+	public void stopProcessing() {
+		// TODO: to be completed
+	}
+
+	/**
+	 * Create an element to display a title
+	 * 
+	 * @param v the logical representation of a title
+	 */
+	private void doTitle(final Title v) {
+		final InlineLabel il = new InlineLabel(v.getText());
+		scriptureHolder.add(il);
+	}
+
+	/**
+	 * Create a display for the verse
+	 * 
+	 * @param v the logical representation of the verse
+	 */
+	private void doVerse(final Verse v) {
+		VerseLabel vl;
+
+		for (final TextualElement text : v.getVerseContent()) {
+			// check that text is not nullable
+			if (text.getText() != null) {
+				vl = new VerseLabel(text.getText(), eventBus);
+				scriptureHolder.add(vl);
+
+				// then do specifics
+				if (text instanceof Word) {
+					final Word w = (Word) text;
+					// if there's an alternative, then we ensure that we set
+					// that up
+					// eventually UI design will mean changes here
+					vl.setAlternativeWord(w.getAlternativeWord());
+
+					final List<String> lemma = w.getLemma();
+					if (lemma != null) {
+						lemmaWords.add(vl);
+						vl.setLemmas(lemma);
+					}
+
+					final List<String> morph = w.getMorph();
+					if (morph != null) {
+						vl.setMorphs(morph);
+						morphs.add(vl);
+					}
+				}
+			}
+		}
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/StepView.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/StepView.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/StepView.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,116 @@
+package com.tyndalehouse.step.web.client.view;
+
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.DockPanel;
+import com.google.gwt.user.client.ui.FlowPanel;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.client.presenter.HistoryModulePresenter;
+import com.tyndalehouse.step.web.client.presenter.ModuleSelectorPresenter;
+import com.tyndalehouse.step.web.client.presenter.ScripturePresenter;
+import com.tyndalehouse.step.web.client.presenter.ScriptureSelectorPresenter;
+import com.tyndalehouse.step.web.client.presenter.StepPresenter;
+import com.tyndalehouse.step.web.client.presenter.TimebandListPresenter;
+import com.tyndalehouse.step.web.client.presenter.TimelinePresenter;
+
+/**
+ * This View sets up the many different views and the layout of the Step
+ * Application
+ * 
+ * @author cjburrell
+ * 
+ */
+public class StepView extends Composite implements StepPresenter.Display {
+
+	/**
+	 * This is the panel on which you display scripture side by side.
+	 */
+	private final DockPanel dp;
+
+	// TODO: i should be able to pass in the ScriptureSelectorPresenter as
+	// opposed to the display directly
+	// we want one that is attached. that would remove the need for
+
+	/**
+	 * 
+	 * Default constructor inputting most presenters, which initialises the
+	 * views via Gin
+	 * 
+	 * @param scriptureSelector a view allowing the user to key in a biblical
+	 *            reference
+	 * @param scripture a view showing scripture
+	 * @param scripture2 a second view showing scripture
+	 * @param moduleSelector a view allowing the user to select his module of
+	 *            interest (history, geography, etc.)
+	 * @param module the view display the various different modules (history,
+	 *            geography, etc.)
+	 * @param timelinePresenter a view allowing the user to show
+	 * @param timebandListPresenter a view showing the current numbers of events
+	 *            displayed on the timeline
+	 *            <p>
+	 *            TODO: experiment if these can be passed in using just the
+	 *            View, but their interface definition for e.g.
+	 *            ScripturePresenter.Display
+	 */
+	@Inject
+	public StepView(final ScriptureSelectorPresenter scriptureSelector,
+		final ScripturePresenter scripture, final ScripturePresenter scripture2,
+		final ModuleSelectorPresenter moduleSelector, final HistoryModulePresenter module,
+		final TimelinePresenter timelinePresenter, final TimebandListPresenter timebandListPresenter) {
+
+		final FlowPanel flow = new FlowPanel();
+
+		dp = new DockPanel();
+		flow.add(dp);
+		initWidget(flow);
+
+		final HorizontalPanel northPanel = new HorizontalPanel();
+
+		dp.add(northPanel, DockPanel.NORTH);
+		northPanel.add(scriptureSelector.getDisplay().asWidget());
+		northPanel.add(moduleSelector.getDisplay().asWidget());
+
+		// scripturePanels = new HorizontalPanel();
+		// dp.add(scripturePanels, DockPanel.WEST);
+		addScriptureDisplay(scripture);
+		addScriptureDisplay(scripture2);
+
+		// starts here hardcoded, each of the scripture panel takes 25%, but
+		// eventually, they
+		// should try and work this out for themselves
+		// TODO: see above
+		scripture.getDisplay().asWidget();
+		scripture2.getDisplay().asWidget();
+
+		dp.add(module.getDisplay().asWidget(), DockPanel.CENTER);
+		flow.add(timelinePresenter.getDisplay().asWidget());
+
+		// for the moment, adding it to the flow
+		dp.add(timebandListPresenter.getDisplay().asWidget(), DockPanel.SOUTH);
+	}
+
+	/**
+	 * adds a scripture display component to the page
+	 * 
+	 * @param scripture scripture "view"
+	 */
+	public void addScriptureDisplay(final ScripturePresenter scripture) {
+		dp.add(scripture.getDisplay().asWidget(), DockPanel.WEST);
+		// scripturePanels.add(scripture.getDisplay().asWidget());
+	}
+
+	public Widget asWidget() {
+		return this;
+	}
+
+	public void startProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void stopProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/TimebandListView.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/TimebandListView.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/TimebandListView.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,99 @@
+package com.tyndalehouse.step.web.client.view;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import net.customware.gwt.presenter.client.EventBus;
+
+import com.google.gwt.event.logical.shared.ValueChangeEvent;
+import com.google.gwt.event.logical.shared.ValueChangeHandler;
+import com.google.gwt.user.client.ui.CheckBox;
+import com.google.gwt.user.client.ui.Composite;
+import com.google.gwt.user.client.ui.VerticalPanel;
+import com.google.gwt.user.client.ui.Widget;
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.client.event.UserInterestInBandEvent;
+import com.tyndalehouse.step.web.client.presenter.TimebandListPresenter;
+import com.tyndalehouse.step.web.client.toolkit.timeline.helpers.CurrentBandStats;
+
+/**
+ * The timeband list view is a list of timebands. The list includes numbers of
+ * events currently on the timeband and the number of events that could be
+ * shown, in the visible section, of the timeband should the user express
+ * interest
+ * 
+ * @author cjburrell
+ * 
+ */
+public class TimebandListView extends Composite implements TimebandListPresenter.Display {
+	/**
+	 * the map of checkboxes displayed on the page
+	 */
+	private final Map<Integer, CheckBox> checkboxes = new HashMap<Integer, CheckBox>();
+
+	/**
+	 * TODO: remove this event bus
+	 */
+	private final EventBus eventBus;
+
+	/**
+	 * the vertical panel on which the checkboxes are added
+	 */
+	private final VerticalPanel fp = new VerticalPanel();
+
+	/**
+	 * The default constructor
+	 * 
+	 * @param eventBus TODO: TO BE REMOVED
+	 */
+	@Inject
+	public TimebandListView(final EventBus eventBus) {
+		this.eventBus = eventBus;
+		initWidget(fp);
+	}
+
+	public Widget asWidget() {
+		return this;
+	}
+
+	public void startProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+
+	public void stopProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+	/**
+	 * method called to update the list of timebands with the latest statistics
+	 * 
+	 * @param stats is a list of current numbers of events (total/visible) on
+	 *            each timeband
+	 */
+	// TODO: should the event adding somehow be moved into the presenter?
+	public void updateList(final List<CurrentBandStats> stats) {
+		for (final CurrentBandStats band : stats) {
+			CheckBox cb = checkboxes.get(band.getBandId());
+			if (cb == null) {
+				cb = new CheckBox();
+				fp.add(cb);
+				cb.addValueChangeHandler(new ValueChangeHandler<Boolean>() {
+					public void onValueChange(final ValueChangeEvent<Boolean> event) {
+						eventBus.fireEvent(new UserInterestInBandEvent(band.getBandId(), event.getValue()));
+					}
+
+				});
+			}
+
+			final int numEventsInBand = band.getNumVisibleElements();
+			cb.setText(band.getBandDescription() + " (" + numEventsInBand + ")");
+			cb.setTitle("Click here to show " + numEventsInBand + " more events.");
+			cb.setValue(band.isUserInterested(), false);
+			checkboxes.put(band.getBandId(), cb);
+		}
+	}
+}

Added: 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	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/client/view/TimelineView.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,104 @@
+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.VerticalPanel;
+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.Timeline;
+
+/**
+ * the timeline view is a wrapper around the whole timeline component used for
+ * displaying events stored in the database. These events can be point-in-time
+ * or in duration.
+ * 
+ * A timeline is split into a timebands, which are then split in to time tracks.
+ * The events are added to a timetrack
+ * 
+ * @author cjburrell
+ * 
+ */
+public class TimelineView extends Composite implements TimelinePresenter.Display {
+
+	/**
+	 * The timeline component
+	 */
+	private final Timeline timeline;
+
+	/**
+	 * The zoom in button
+	 */
+	private final Button zoomIn;
+
+	/**
+	 * The zoom out button
+	 */
+	private final Button zoomOut;
+
+	/**
+	 * Default constructor TODO: remove eventBus
+	 * 
+	 * @param eventBus remove event bus from here
+	 */
+	@Inject
+	public TimelineView(final EventBus eventBus) {
+		// to do a custom timeline for testing
+		// TODO: change to a provider, lookup Gin/Guice manual to do this...
+		timeline = new Timeline(eventBus);
+
+		final VerticalPanel vp = new VerticalPanel();
+		final FlowPanel fp = new FlowPanel();
+		vp.add(fp);
+		vp.setWidth("100%");
+
+		zoomIn = new Button("+");
+		zoomOut = new Button("-");
+		zoomIn.setStyleName("step-timeline-control");
+		zoomOut.setStyleName("step-timeline-control");
+
+		fp.add(zoomIn);
+		fp.add(zoomOut);
+		vp.add(timeline);
+		initWidget(vp);
+	}
+
+	public Widget asWidget() {
+		return this;
+	}
+
+	/**
+	 * @return the timeline
+	 */
+	public Timeline getTimeline() {
+		return timeline;
+	}
+
+	/**
+	 * @return A click handler on which to register an event for zooming in
+	 */
+	public HasClickHandlers getZoomIn() {
+		return zoomIn;
+	}
+
+	/**
+	 * @return A click handler on which to register an event for zooming out
+	 */
+	public HasClickHandlers getZoomOut() {
+		return zoomOut;
+	}
+
+	public void startProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+
+	public void stopProcessing() {
+		// TODO Auto-generated method stub
+
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/AbstractStepHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/AbstractStepHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/AbstractStepHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,44 @@
+package com.tyndalehouse.step.web.server.common;
+
+import java.lang.reflect.ParameterizedType;
+
+import net.customware.gwt.dispatch.server.ActionHandler;
+import net.customware.gwt.dispatch.shared.Action;
+import net.customware.gwt.dispatch.shared.Result;
+
+import org.apache.log4j.Logger;
+
+/**
+ * To abstract away the need for declaring getActionType every time.
+ * 
+ * @author CJBurrell
+ * 
+ * @param <A> the action in question
+ * @param <R> the response to be sent back to the client
+ */
+public abstract class AbstractStepHandler<A extends Action<R>, R extends Result> implements
+	ActionHandler<A, R> {
+
+	/**
+	 * Logger for a particular instance of a handler
+	 */
+	private final Logger logger = Logger.getLogger(this.getClass());
+
+	@SuppressWarnings("unchecked")
+	/*
+	 * returns the type of the action
+	 * 
+	 * @return the type of the action
+	 */
+	public final Class<A> getActionType() {
+		final ParameterizedType pt = (ParameterizedType) getClass().getGenericSuperclass();
+		return (Class<A>) pt.getActualTypeArguments()[0];
+	}
+
+	/**
+	 * @return the logger
+	 */
+	protected final Logger getLogger() {
+		return logger;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/ConfigNotLoadedException.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/ConfigNotLoadedException.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/ConfigNotLoadedException.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,28 @@
+package com.tyndalehouse.step.web.server.common;
+
+/**
+ * an exceptoin to indicate that the configuration properties have not been
+ * loaded
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class ConfigNotLoadedException extends Exception {
+
+	/**
+	 * serial id for serialization
+	 */
+	private static final long serialVersionUID = 1644291687028980017L;
+
+	/**
+	 * public constructor an exceptoin to indicate that the configuration
+	 * properties have not been loaded
+	 * 
+	 * @param e
+	 *            the base exception
+	 */
+	public ConfigNotLoadedException(final Exception e) {
+		super("The configuration files could not be loaded", e);
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/ConfigProvider.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/ConfigProvider.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/ConfigProvider.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,85 @@
+package com.tyndalehouse.step.web.server.common;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.Properties;
+
+/**
+ * Config Provider for Step. 
+ * TODO: Possibly should be rewritten to have a Guice element to it, with @Singleton tag 
+ * @author CJBurrell
+ *
+ */
+public final class ConfigProvider {
+	/**
+	 * internal static provider
+	 */
+	private static ConfigProvider pr;
+		
+	/**
+	 * Internal properties object
+	 */
+	private Properties p = new Properties();
+
+	/**
+	 * private constructor to prevent initialisation.
+	 * @throws ConfigNotLoadedException exception should it fail to look up the parameter name
+	 */
+	private ConfigProvider() throws ConfigNotLoadedException {
+		load();
+	}
+
+	/**
+	 * Loads or reloads a properties file from the classpath.
+	 * TODO: investigate issue with concurrency here, since we might access p before it's fully loaded...
+	 * @throws ConfigNotLoadedException  exception should it fail to look up the parameter name
+	 */
+	public void load() throws ConfigNotLoadedException {
+		ClassLoader loader = Thread.currentThread().getContextClassLoader();
+		URL url = loader.getResource("com/tyndalehouse/step/web/server/config/environment.properties");
+		try {
+			p.load(url.openStream());
+		} catch (IOException e) {
+			throw new ConfigNotLoadedException(e);
+		}
+	}
+
+	/**
+	 * Gets the value of a param.
+	 * @param name the name of the param
+	 * @return the value of the param
+	 * @throws ConfigNotLoadedException A problem occured during loading of the config
+	 */
+	public synchronized static String get(final String name) throws ConfigNotLoadedException {
+		if (pr == null) {
+			pr = new ConfigProvider();
+		}
+		
+		String value = System.getProperty(name);
+		if(value == null) {
+			value = pr.readProperty(name);
+		}
+		
+		return value;
+		
+	}
+
+	/**
+	 * reads a property on the properties object.
+	 * @param name name of the property
+	 * @return the value
+	 */
+	private String readProperty(final String name) {
+		return p.getProperty(name);
+	}
+
+	/**
+	 * returns an integer corresponding to the name of the parameter.
+	 * @param paramName the name of the parameter
+	 * @return an integer value for paramName
+	 * @throws ConfigNotLoadedException exception should it fail to look up the parameter name
+	 */
+	public static int getInt(final String paramName) throws ConfigNotLoadedException {
+		return Integer.parseInt(get(paramName));
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/JSwordConstants.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/JSwordConstants.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/common/JSwordConstants.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,50 @@
+package com.tyndalehouse.step.web.server.common;
+
+/**
+ * Constants to map back to the correct JSword modules, index entries
+ * @author CJBurrell
+ *
+ */
+public final class JSwordConstants {
+	/**
+	 * the pattern with which strong references in OSIS start
+	 */
+	public static final String STRONG_PATTERN_START = "strong:";
+	
+	/**
+	 * a greek marker for strong numbers, e.g. strong:Gxxxx
+	 */
+	public static final char STRONG_GREEK_MARKER = 'G';
+	
+	/**
+	 * Strong hebrew marker, for e.g. strong:Hxxxx
+	 */
+	public static final char STRONG_HEBREW_MARKER = 'H';
+	
+	/**
+	 * Initials of default Hebrew JSword module to use for lookup of dictionary definitions
+	 */
+	public static final String STRONG_HEBREW_DICTIONARY_INITIALS = "StrongsHebrew";
+	
+	/**
+	 * Initials of default Strong JSword greek dictionary module for lookup of dictionary definitions
+	 */
+	public static final String STRONG_GREEK_DICTIONARY_INITIALS = "StrongsGreek";
+	
+	/**
+	 * Default hebrew text for interlinear purposes
+	 */
+	public static final String DEFAULT_HEBREW_INTERLINEAR_TEXT = "LXX";
+
+	//TODO:This gives us greek!
+	/**
+	 * Default Greek text for interlinear purposes
+	 */
+	public static final String DEFAULT_GREEK_INTERLINEAR_TEXT = "BYZ";
+
+	/**
+	 * hiding default constructor
+	 */
+	private JSwordConstants() {
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/MalformedStepQueryException.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/MalformedStepQueryException.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/MalformedStepQueryException.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,39 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+/**
+ * Query to be thrown if the query file cannot be parsed by our framework.
+ * @author CJBurrell
+ *
+ */
+public class MalformedStepQueryException extends Exception {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -3607780460262284122L;
+
+	/**
+	 * to instantiate the exception when a particular parameter name is incorrect
+	 * @param paramName parameter name that is incorrect
+	 * @param sql sql in which parameter name was incorrect
+	 */
+	public MalformedStepQueryException(final String paramName, final String sql) {
+		super(String.format("The argument %s was not recognised in query:\n %s", paramName, sql));
+	}
+
+	/**
+	 * @param message the message
+	 * @param ex base exception to be passed up to the super class
+	 */
+	public MalformedStepQueryException(final String message, final Exception ex) {
+		super(message, ex);
+	}
+
+	/**
+	 * 
+	 * @param message simple message to instantiate the default exception
+	 */
+	public MalformedStepQueryException(final String message) {
+		super(message);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/Query.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/Query.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/Query.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,20 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+/**
+ * The interface for any enum describing the queries to be run
+ * @author CJBurrell
+ *
+ */
+public interface Query {
+	/**
+	 * @return the component name
+	 */
+	String getComponent();
+
+	/**
+	 * returns the name of the enum
+	 * 
+	 * @return the name of the query
+	 */
+	String name();
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/QueryImpl.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/QueryImpl.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/QueryImpl.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,50 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+/**
+ * List of queries to be executed against DB
+ * 
+ * @author CJBurrell
+ * 
+ */
+public enum QueryImpl implements Query {
+	/**
+	 * gets events for a particular date range
+	 */
+	GET_EVENTS_FOR_DATE_RANGE("timeline"),
+
+	/**
+	 * gets timeline description data
+	 */
+	GET_TIMELINE_SETUP_DATA("timeline"),
+
+	/**
+	 * looks up which is the closest event, and on which timeline a given
+	 * scripture passage is
+	 */
+	LOOKUP_TIMELINE_ORIGIN("timeline");
+
+	/**
+	 * component (folder) in which the component can be found
+	 */
+	private final String component;
+
+	/**
+	 * default constructor for this enum
+	 * 
+	 * @param component component/folder where the query resides
+	 */
+	QueryImpl(final String component) {
+		this.component = component;
+	}
+
+	/**
+	 * (non-Javadoc)
+	 * 
+	 * @see com.tyndalehouse.step.web.server.db.framework.Query#getComponent()
+	 * @return component/folder where the query resides
+	 */
+	public String getComponent() {
+		return component;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/ResultSetProcessor.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/ResultSetProcessor.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/ResultSetProcessor.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,43 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Map;
+
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+
+/**
+ * @author CJBurrell This is used by the query runner to process result sets
+ * @param <T> the type of bean to be returned
+ */
+public interface ResultSetProcessor<T> {
+	/**
+	 * returns the parameters. Typically this would only be called by the query
+	 * framework
+	 * 
+	 * @return a map, mapping the parameter name to the object to be passed into
+	 *         the query (generally native types or Strings)
+	 */
+	Map<String, Object> getParameters();
+
+	/**
+	 * Returns the enum defining which query should be executed.
+	 * 
+	 * @return the query to be executed.
+	 */
+	Query getQuery();
+
+	/**
+	 * This method will be called after a query has been run by the query
+	 * framework. It returns a list of beans to the caller
+	 * 
+	 * @param rs ResultSet to be processed
+	 * @return a list of beans to the UI of type T
+	 * @throws MalformedStepQueryException the query run was malformed
+	 * @throws ConfigNotLoadedException an error occured during the loading of
+	 *             the database config
+	 * @throws SQLException a SQL exception occurred
+	 */
+	List<T> process(ResultSet rs) throws MalformedStepQueryException, ConfigNotLoadedException, SQLException;
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQuery.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQuery.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQuery.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,158 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Step Query to be executed against the database. This this is then given to
+ * the StepQueryRunner and executed It contains the list of arguments, the types
+ * of those parameters and the sql statement to be executed
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class StepQuery {
+	/**
+	 * list of expected arguments
+	 */
+	private final List<String> arguments;
+
+	/**
+	 * the types of the expected parameters
+	 */
+	private final Map<String, Integer> paramTypes;
+
+	/**
+	 * the SQL statements
+	 */
+	private String sql;
+
+	/**
+	 * public constructor which initialises the arguments and parameters.
+	 */
+	public StepQuery() {
+		arguments = new ArrayList<String>();
+		paramTypes = new HashMap<String, Integer>();
+	}
+
+	/**
+	 * adding an argument as found in the query definition: e.g. <code>
+	 * select 1 from table where value = #paramName#
+	 * </code>
+	 * 
+	 * @param paramName param name to be added to the query definition
+	 * 
+	 */
+	public void addArgument(final String paramName) {
+		arguments.add(paramName);
+	}
+
+	/**
+	 * addings a mapping from the definitions at the top of the file
+	 * 
+	 * @param paramName parameter name
+	 * @param type type of the parameter
+	 */
+	public void addParamTypeMapping(final String paramName, final Integer type) {
+		paramTypes.put(paramName, type);
+	}
+
+	/**
+	 * returns the SQL that gets executed
+	 * 
+	 * @return the SQL query
+	 */
+	public String getSQLText() {
+		return sql;
+	}
+
+	/**
+	 * Sets the sql for the step query to be run
+	 * 
+	 * @param sql sql representing the query to be run
+	 */
+	public void setSQLText(final String sql) {
+		this.sql = sql;
+	}
+
+	/**
+	 * Sets up the prepared statement arguments in the correct order.
+	 * 
+	 * @param ps the prepared statement
+	 * @param passedArguments the map of named arguments
+	 * @throws SQLException this is thrown if the passed in arguments do not
+	 *             match the expected parameters as loaded from disk
+	 * 
+	 */
+	public void setupParameters(final PreparedStatement ps, final Map<String, Object> passedArguments)
+			throws SQLException {
+		int argIndex = 1;
+		for (final String argName : arguments) {
+			setArgument(ps, paramTypes.get(argName), passedArguments.get(argName), argIndex++);
+		}
+	}
+
+	/**
+	 * Validates the query loaded, to ensure that the number of arguments found
+	 * in the query match the number of arguments found in the declarations
+	 * 
+	 * @throws MalformedStepQueryException this is thrown if the validation
+	 *             fails
+	 */
+	public void validate() throws MalformedStepQueryException {
+		for (final String arg : arguments) {
+			if (!paramTypes.containsKey(arg)) {
+				throw new MalformedStepQueryException(arg, sql);
+			}
+		}
+
+		// TODO: optimize by compiling prepared statement here!
+	}
+
+	/**
+	 * Sets up the parameter into the prepared statement
+	 * 
+	 * @param ps prepared statement
+	 * @param sqlType the type of the parameter
+	 * @param value the value of the parameter
+	 * @param argIndex the position at which the parameter is to be placed in
+	 *            the prepared statement
+	 * @throws SQLException an exception thrown in case something goes wrong
+	 */
+	private void setArgument(final PreparedStatement ps, final int sqlType, final Object value,
+			final int argIndex) throws SQLException {
+		// check for null first
+		if (value == null) {
+			ps.setNull(argIndex, sqlType);
+			return;
+		}
+
+		// at this stage, we do not need to worry about null variables
+		switch (sqlType) {
+		case Types.INTEGER:
+			ps.setInt(argIndex, (Integer) value);
+			break;
+		case Types.VARCHAR:
+			ps.setString(argIndex, (String) value);
+			break;
+		case Types.BIGINT:
+			ps.setLong(argIndex, (Long) value);
+			break;
+		case Types.SMALLINT:
+			ps.setShort(argIndex, (Short) value);
+			break;
+		case Types.LONGVARCHAR:
+			ps.setString(argIndex, (String) value);
+			break;
+		default:
+			throw new SQLException(String.format(
+					"The STEP query framework does not yet support this type/value (%d, %s)", sqlType, value
+							.toString()));
+		}
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunner.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunner.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunner.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,35 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+import java.util.List;
+
+/**
+ * StepQueryRunner interface defining what should be present for the clients to
+ * use this as a library
+ * 
+ * @author CJBurrell
+ * 
+ */
+public interface StepQueryRunner {
+
+	/**
+	 * Clears the cache of parsed queries that are currently in the query runner
+	 */
+	void clearCache();
+
+	/**
+	 * Tears down the database pool and starts it up again
+	 */
+	void restartDatasourcePool();
+
+	/**
+	 * To run a query in the database
+	 * 
+	 * @param <T> Type of bean to be returned
+	 * @param processor Processor to be invoked: @see {@link ResultSetProcessor}
+	 * @return a list of beans of type T
+	 * @throws UnableToRunQueryException if the configuration was not loaded or
+	 *             a sql exception during parsing or execution of the call
+	 */
+	<T> List<T> run(final ResultSetProcessor<T> processor) throws UnableToRunQueryException;
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunnerImpl.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunnerImpl.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/StepQueryRunnerImpl.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,356 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.HashMap;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.sql.DataSource;
+
+import org.apache.commons.dbcp.BasicDataSource;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.logging.Log;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+import com.tyndalehouse.step.web.server.common.ConfigProvider;
+
+/**
+ * This class is the crux of the database access. An enum identifies the SQL
+ * file to be loaded. Arguments get defined in the query file as define
+ * variableName as sqlType A map can be passed in that ensures all arguments are
+ * mapped to the correct location in the prepared statement
+ * 
+ * @author CJBurrell
+ */
+ at Singleton
+public class StepQueryRunnerImpl implements StepQueryRunner {
+	/**
+	 * query to indicate whether to cache prepared statements. Currently doesn't
+	 * work well with Apache Derby
+	 */
+	private static final Object CACHE_QUERY_PROPERTY = "query.runner.cache";
+
+	/**
+	 * Datasource object which gets loaded through a conection pool
+	 */
+	private static DataSource datasource = null;
+
+	/**
+	 * pattern definition of a declaration of argument at the top of a SQL file
+	 */
+	private static final String DEFINITION_PATTERN = "define (\\w+) as (\\w+)";
+
+	/**
+	 * the HASH character
+	 */
+	private static final String HASH = "#";
+
+	/**
+	 * the hashmap containing the cache of all queries
+	 */
+	private static HashMap<Query, StepQuery> queries = new HashMap<Query, StepQuery>();
+
+	/**
+	 * the ?, QUESTION MARK character
+	 */
+	private static final String QUESTION_MARK = "?";
+
+	/**
+	 * a pointer to the Log4J log
+	 */
+	private final Log log;
+
+	/**
+	 * prevent instantiation
+	 * 
+	 * @param log default logger to use throughout implementation
+	 */
+	@Inject
+	public StepQueryRunnerImpl(final Log log) {
+		this.log = log;
+	}
+
+	public void clearCache() {
+		queries.clear();
+	}
+
+	public void restartDatasourcePool() {
+		// TODO: feature is to kill off all connections, and reload it.
+
+	}
+
+	/**
+	 * returns a list of beans of type T
+	 * 
+	 * @param processor processor to be used
+	 * @param <T> the type of the bean to be returned
+	 * @return list of beans of type T
+	 * @throws UnableToRunQueryException unable to run the query for various
+	 *             reasons
+	 * @see com.tyndalehouse.step.web.server.db.StepQueryRunner#run(com.tyndalehouse
+	 *      .step.web.server.db.ResultSetProcessor)
+	 */
+	public <T> List<T> run(final ResultSetProcessor<T> processor) throws UnableToRunQueryException {
+		ResultSet rs;
+		Connection connection = null;
+		PreparedStatement ps = null;
+
+		// check for null
+		if (processor == null) {
+			log.error("The passed in ResultSetProcessor was null.");
+			throw new UnableToRunQueryException(new NullPointerException());
+		}
+
+		final long tInit = System.currentTimeMillis();
+		StepQuery stepQuery = null;
+		try {
+			stepQuery = prepareStepQuery(processor.getQuery());
+
+			final long tAfterLoad = System.currentTimeMillis();
+			connection = datasource.getConnection();
+			ps = connection.prepareStatement(stepQuery.getSQLText());
+
+			final long tAfterParse = System.currentTimeMillis();
+			stepQuery.setupParameters(ps, processor.getParameters());
+
+			logStepQuery(processor, stepQuery);
+			final long tAfterLog = System.currentTimeMillis();
+
+			// TODO: not returning anything!
+			rs = ps.executeQuery();
+			final long tAfterExecute = System.currentTimeMillis();
+
+			final List<T> results = processor.process(rs);
+			final long tAfterParseResults = System.currentTimeMillis();
+
+			if (log.isInfoEnabled()) {
+				log.info(String.format("StepQueryRunner (load, parse, execute, return) = (%d, %d, %d, %d)",
+						tAfterLoad - tInit, tAfterParse - tAfterLoad, tAfterExecute - tAfterLog,
+						tAfterParseResults - tAfterExecute));
+			}
+
+			return results;
+		} catch (final ConfigNotLoadedException e) {
+			log.error("Unable to load the configuration file to set up datasource.");
+			throw new UnableToRunQueryException(e, stepQuery);
+		} catch (final MalformedStepQueryException e) {
+			log.error("An exception occured during the execution of the sql query");
+			throw new UnableToRunQueryException(e, stepQuery);
+		} catch (final SQLException e) {
+			log.error("An exception occured file trying to locate the file.");
+			throw new UnableToRunQueryException(e, stepQuery);
+		} finally {
+			// close the statement
+			if (ps != null) {
+				try {
+					ps.close();
+				} catch (final SQLException exception) {
+					log.error("Error finalising connection", exception);
+				}
+			}
+
+			// close the connection
+			if (connection != null) {
+				try {
+					connection.close();
+				} catch (final SQLException exception) {
+					log.error("Error finalising connection", exception);
+				}
+			}
+		}
+	}
+
+	/**
+	 * if logging is enabled at trace level, then the query is output, with all
+	 * its parameters
+	 * 
+	 * @param processor processor to process results of the query, which
+	 *            contains the parameters
+	 * @param stepQuery the query to be logged
+	 */
+	private void logStepQuery(final ResultSetProcessor<?> processor, final StepQuery stepQuery) {
+		if (log.isTraceEnabled()) {
+			final StringBuffer logOutput = new StringBuffer();
+			logOutput.append("Query is: ");
+			logOutput.append(stepQuery.getSQLText());
+
+			for (final String paramName : processor.getParameters().keySet()) {
+				logOutput.append(' ');
+				logOutput.append(paramName);
+				logOutput.append('=');
+				logOutput.append(processor.getParameters().get(paramName));
+				logOutput.append(", ");
+			}
+			log.trace(logOutput.toString());
+		}
+	}
+
+	/**
+	 * Faster than a regexp, so use this , in which we expect that there are
+	 * arguments to be parsed These would be defined as #query-param# within the
+	 * sql text. The function works by looking for a open and then a closed #
+	 * Unfortunately, it is not perfect and will have TODO; be rewritten to
+	 * ensure that the programmer can use the charact # in his query
+	 * 
+	 * @param q is the query
+	 * @return a object of type {@link StepQuery}
+	 */
+	private StepQuery parseArguments(final StringBuffer q) {
+		final StepQuery query = new StepQuery();
+
+		int openingHash = 0;
+		while ((openingHash = q.indexOf(HASH)) != -1) {
+			final int endingHash = q.indexOf(HASH, openingHash + 1);
+			final String paramName = q.substring(openingHash + 1, endingHash);
+			query.addArgument(paramName);
+			q.replace(openingHash, endingHash + 1, QUESTION_MARK);
+		}
+
+		return query;
+	}
+
+	/**
+	 * Look for all lines containing the pattern define variable_name as type
+	 * Then removes those into a map before continuing
+	 * 
+	 * @param queryText sql text as loaded from disk
+	 * @param q query text to look through
+	 * @return a object of type {@link StepQuery}
+	 * @throws MalformedStepQueryException an exception is thrown to indicate an
+	 */
+	private StepQuery parseDefinitions(final StringBuffer queryText, final StepQuery q)
+			throws MalformedStepQueryException {
+		// all sql files with parameters will have definitions for their
+		// parameters at the top.
+		final Pattern p = Pattern.compile(DEFINITION_PATTERN);
+		final Matcher m = p.matcher(queryText);
+
+		// iterate through definitions that have been found
+		while (m.find()) {
+			final String paramName = m.group(1);
+			final String paramType = m.group(2);
+
+			try {
+				final Integer type = Types.class.getField(paramType.toUpperCase()).getInt(null);
+				q.addParamTypeMapping(paramName, type);
+			} catch (final IllegalArgumentException e) {
+				throw new MalformedStepQueryException(String.format("Could not parse argument type: %s",
+						paramType), e);
+			} catch (final SecurityException e) {
+				throw new MalformedStepQueryException(String.format("Could not parse argument type: %s",
+						paramType), e);
+			} catch (final IllegalAccessException e) {
+				throw new MalformedStepQueryException(String.format("Could not parse argument type: %s",
+						paramType), e);
+			} catch (final NoSuchFieldException e) {
+				throw new MalformedStepQueryException(String.format("Could not parse argument type: %s",
+						paramType), e);
+			}
+		}
+
+		q.setSQLText(m.replaceAll(""));
+		return q;
+	}
+
+	/**
+	 * @param query query to be executed. If already cached, then this query is
+	 *            returned otherwise, it is loaded from disk
+	 * @return a object of type {@link StepQuery}
+	 * @throws ConfigNotLoadedException if an issue occured during loading of
+	 *             the configuration for STEP
+	 * @throws MalformedStepQueryException an exception is thrown to indicate an
+	 *             issue with the sql file that could not be parsed
+	 */
+	private StepQuery prepareStepQuery(final Query query) throws ConfigNotLoadedException,
+			MalformedStepQueryException {
+		StepQuery stepQuery = queries.get(query);
+		// check whether query is in cache
+		if (stepQuery == null) {
+			stepQuery = readQueryFromFile(query);
+		}
+
+		// now check if datasource is null
+		if (datasource == null) {
+			datasource = setupDatasource();
+		}
+		return stepQuery;
+	}
+
+	/**
+	 * Reads a query from the file
+	 * 
+	 * @param query query to be loaded
+	 * @return returns a loaded {@link StepQuery} object
+	 * @throws ConfigNotLoadedException failed to load the configuration
+	 * @throws MalformedStepQueryException thrown if arguments found don't match
+	 *             a declaration
+	 */
+	private StepQuery readQueryFromFile(final Query query) throws ConfigNotLoadedException,
+			MalformedStepQueryException {
+		// get base path from file
+		final String basePath = ConfigProvider.get("query.repository.path");
+		final String baseComponent = query.getComponent();
+		final String filenameBase = query.name();
+
+		// read query from file
+		final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+		final String filename = String.format("%s%s/%s.sql", basePath, baseComponent, filenameBase
+				.toLowerCase());
+		final URL fileLocation = loader.getResource(filename);
+		StepQuery stepQuery = null;
+		StringBuffer q;
+
+		// check file location is non null:
+		if (fileLocation == null) {
+			throw new MalformedStepQueryException(String.format("The filename %s does not exist.", filename));
+		}
+
+		try {
+			q = new StringBuffer(FileUtils.readFileToString(new File(fileLocation.getFile())));
+			stepQuery = parseDefinitions(q, parseArguments(q));
+			stepQuery.validate();
+
+			// check whether or not to cache the query:
+			if (ConfigProvider.get("query.runner.cache").equals(CACHE_QUERY_PROPERTY)) {
+				queries.put(query, stepQuery);
+			}
+		} catch (final IOException e) {
+			throw new MalformedStepQueryException(
+					String.format("Error reading query file: %s", filenameBase), e);
+		}
+
+		return stepQuery;
+	}
+
+	/**
+	 * sets up the datasource from properties
+	 * 
+	 * @return the datasource properly configured
+	 * @throws ConfigNotLoadedException throws if properties aren't found
+	 */
+	private DataSource setupDatasource() throws ConfigNotLoadedException {
+		final BasicDataSource ds = new BasicDataSource();
+		ds.setDriverClassName(ConfigProvider.get("db.driver"));
+		ds.setUsername(ConfigProvider.get("db.user"));
+		ds.setPassword(ConfigProvider.get("db.password"));
+		ds.setUrl(ConfigProvider.get("connection.string"));
+		ds.setInitialSize(ConfigProvider.getInt("db.pool.initialSize"));
+		ds.setMaxActive(ConfigProvider.getInt("db.pool.maxSize"));
+		// ds.setValidationQuery(ConfigProvider.get("db.pool.validation.query"));
+		// ds.setPoolPreparedStatements(true); //NOT Supported by java DB :(
+		ds.setMaxOpenPreparedStatements(ConfigProvider.getInt("db.pool.prepared.size"));
+		ds.setDefaultAutoCommit(false);
+
+		return ds;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/UnableToRunQueryException.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/UnableToRunQueryException.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/framework/UnableToRunQueryException.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,56 @@
+package com.tyndalehouse.step.web.server.db.framework;
+
+/**
+ * An issue occurred during the parsing or running of a query
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class UnableToRunQueryException extends Exception {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -7810594097160119720L;
+
+	/**
+	 * The StepQuery at the origin of the exception
+	 */
+	private StepQuery stepQuery;
+
+	/**
+	 * Pass in the root cause of the exception
+	 * 
+	 * @param e the root exception
+	 */
+	public UnableToRunQueryException(final Exception e) {
+		super(e);
+	}
+
+	/**
+	 * Unable to run a query exception, with the stepQuery itself, and the root
+	 * exception
+	 * 
+	 * @param e the exception to be wrapped
+	 * @param stepQuery a step query that was attempted to be executed
+	 */
+	public UnableToRunQueryException(final Exception e, final StepQuery stepQuery) {
+		this(e);
+		this.stepQuery = stepQuery;
+	}
+
+	/**
+	 * @return the stepQuery
+	 */
+	public final StepQuery getStepQuery() {
+		return stepQuery;
+	}
+
+	/**
+	 * @param stepQuery the stepQuery to set
+	 */
+	public final void setStepQuery(final StepQuery stepQuery) {
+		this.stepQuery = stepQuery;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimeBandVisibleDateProcessor.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimeBandVisibleDateProcessor.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimeBandVisibleDateProcessor.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,134 @@
+package com.tyndalehouse.step.web.server.db.timeline;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+import com.tyndalehouse.step.web.server.db.framework.MalformedStepQueryException;
+import com.tyndalehouse.step.web.server.db.framework.Query;
+import com.tyndalehouse.step.web.server.db.framework.QueryImpl;
+import com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineEventBean;
+
+/**
+ * Processes a list of timebands from the database
+ * @author CJBurrell cjburrell
+ *
+ */
+public class TimeBandVisibleDateProcessor implements ResultSetProcessor<TimelineEventBean> {
+
+	/**
+	 * event type id
+	 */
+	private static final String EVENT_TYPE_ID = "event_type_id";
+	/**
+	 * certainty
+	 */
+	private static final String CERTAINTY = "certainty";
+	/**
+	 * importance if
+	 */
+	private static final String IMPORTANCE_ID = "importance_id";
+	/**
+	 * timeband id
+	 */
+	private static final String TIMEBAND_ID = "timeband_id";
+	/**
+	 * name
+	 */
+	private static final String NAME = "name";
+	/**
+	 * to precision
+	 */
+	private static final String TO_PRECISION = "to_precision";
+	/**
+	 * from precision
+	 */
+	private static final String FROM_PRECISION = "from_precision";
+	/**
+	 * to date
+	 */
+	private static final String TO_DATE = "to_date";
+	/**
+	 * from date
+	 */
+	private static final String FROM_DATE = "from_date";
+	/**
+	 * event id
+	 */
+	private static final String EVENT_ID = "event_id";
+	/**
+	 * min date
+	 */
+	private static final String MIN_DATE = "min_date";
+	/**
+	 * max date 
+	 */
+	private static final String MAX_DATE = "max_date";
+	/**
+	 * params to be passed in to the query
+	 */
+	private Map<String, Object> params;
+
+	/**
+	 * public constructor to create the processor with default parameters
+	 * @param minDate min date to be passed to the query
+	 * @param maxDate max date to be passed to the query
+	 * @param timebandId the timeband id to be looked up
+	 */
+	public TimeBandVisibleDateProcessor(final long minDate, final long maxDate, final int timebandId) {
+		params = new HashMap<String, Object>();
+		params.put(MIN_DATE, minDate);
+		params.put(MAX_DATE, maxDate);
+		params.put(TIMEBAND_ID, timebandId);
+	}
+
+
+	/**
+	 * @see {@link ResultSetProcessor}
+	 * @return the map of parameters
+	 */
+	public final Map<String, Object> getParameters() {
+		return params;
+	}
+
+	
+	/**
+	 * @see {@link ResultSetProcessor}
+	 * @return the query to be executed
+	 */
+	public final Query getQuery() {
+		return QueryImpl.GET_EVENTS_FOR_DATE_RANGE;
+	}
+
+	/**
+	 * 
+	 * @param rs result set to be processed
+	 * @see com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor#process(java.sql.ResultSet)
+	 * @return a list of {@link TimelineEventBean} returned by the query
+	 * @exception MalformedStepQueryException an error occurred during the execution of the query
+	 * @exception ConfigNotLoadedException an error occurred during the loading of the configuration
+	 * @exception SQLException an runtime SQL exception occurred
+	 */
+	public final List<TimelineEventBean> process(final ResultSet rs) 
+		throws MalformedStepQueryException, ConfigNotLoadedException, SQLException {
+		// TODO: parse the event in some object, as opposed to just fields like
+		// that!
+		// in particular the precision type
+		List<TimelineEventBean> events = new ArrayList<TimelineEventBean>();
+		while (rs.next()) {
+			Long toDate = rs.getObject(TO_DATE) == null ? null : rs.getLong(TO_DATE);
+			TimelineEventBean teb = new TimelineEventBean(rs.getInt(EVENT_ID), rs.getLong(FROM_DATE), 
+					toDate, 
+					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));
+			events.add(teb);
+		}
+		return events;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginDbBean.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginDbBean.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginDbBean.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,75 @@
+package com.tyndalehouse.step.web.server.db.timeline;
+
+import com.tyndalehouse.step.web.shared.timeline.Unit;
+
+/**
+ * Timeline Origin DB Bean, containing the default configuration for each timeband
+ * @author CJBurrell
+ *
+ */
+public class TimelineOriginDbBean {
+
+	
+	/**
+	 * origin in time (milli seconds since epoch)
+	 */
+	private long origin;
+	/**
+	 * recommended time unit to be displayed
+	 */
+	private Unit unit;
+	
+	/**
+	 * timeband id to be looked up 
+	 */
+	private int timebandId;
+
+	/**
+	 * @return the origin
+	 */
+	public final long getOrigin() {
+		return origin;
+	}
+
+	/**
+	 * @return the unit
+	 */
+	public final Unit getUnit() {
+		return unit;
+	}
+
+	/**
+	 * Sets the origin field
+	 * @param origin value in ms for oring
+	 */
+	public final void setOrigin(final long origin) {
+		this.origin = origin;
+	}
+
+	/**
+	 * Sets the unit for the bean
+	 * 
+	 * @param unit
+	 *            unit that should be shown on screen
+	 */
+	public final void setUnit(final String unit) {
+		this.unit = Unit.valueOf(unit);
+	}
+
+	/**
+	 * returns the timeband id
+	 * @return timeband id
+	 */
+	public final int getTimebandId() {
+		return timebandId;
+	}
+
+	/**
+	 * @param timebandId
+	 *            the timebandId to set
+	 */
+	public final void setTimebandId(final int timebandId) {
+		this.timebandId = timebandId;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginProcessor.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginProcessor.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineOriginProcessor.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,77 @@
+package com.tyndalehouse.step.web.server.db.timeline;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+import com.tyndalehouse.step.web.server.db.framework.MalformedStepQueryException;
+import com.tyndalehouse.step.web.server.db.framework.Query;
+import com.tyndalehouse.step.web.server.db.framework.QueryImpl;
+import com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor;
+
+/**
+ * Step Processor to retrieve the origin event, given a scripture passage
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimelineOriginProcessor implements ResultSetProcessor<TimelineOriginDbBean> {
+	/** result column origin */
+	private static final String ORIGIN = "origin";
+
+	/** input qry end,, verse no for which to restrict the query */
+	private static final String QRY_END = "qry_end";
+
+	/** input qry start, verse no for which to restrict the query */
+	private static final String QRY_START = "qry_start";
+
+	/** result column timeband id */
+	private static final String TIMEBAND = "timeband_id";
+
+	// TODO: move to enum
+	/** result column unit */
+	private static final String UNIT = "unit";
+
+	/** parameters to pass in to the query */
+	private final Map<String, Object> params;
+
+	/**
+	 * Given a scripture range, it
+	 * 
+	 * @param qryStart minimum verse no to restrict range lookup
+	 * @param qryEnd maximum verse no to restrict range lookup
+	 */
+	public TimelineOriginProcessor(final int qryStart, final int qryEnd) {
+		params = new HashMap<String, Object>();
+		params.put(QRY_START, qryStart);
+		params.put(QRY_END, qryEnd);
+	}
+
+	public Map<String, Object> getParameters() {
+		return params;
+
+	}
+
+	public Query getQuery() {
+		return QueryImpl.LOOKUP_TIMELINE_ORIGIN;
+	}
+
+	public List<TimelineOriginDbBean> process(final ResultSet rs) throws MalformedStepQueryException,
+			ConfigNotLoadedException, SQLException {
+		final List<TimelineOriginDbBean> origins = new ArrayList<TimelineOriginDbBean>();
+
+		while (rs.next()) {
+			final TimelineOriginDbBean bean = new TimelineOriginDbBean();
+			bean.setOrigin(rs.getLong(ORIGIN));
+			bean.setUnit(rs.getString(UNIT));
+			bean.setTimebandId(rs.getInt(TIMEBAND));
+			origins.add(bean);
+		}
+		return origins;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineSetupDataProcessor.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineSetupDataProcessor.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/db/timeline/TimelineSetupDataProcessor.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,69 @@
+package com.tyndalehouse.step.web.server.db.timeline;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.tyndalehouse.step.web.server.common.ConfigNotLoadedException;
+import com.tyndalehouse.step.web.server.db.framework.MalformedStepQueryException;
+import com.tyndalehouse.step.web.server.db.framework.Query;
+import com.tyndalehouse.step.web.server.db.framework.QueryImpl;
+import com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineBean;
+
+/**
+ * Data processor for the Step Query framework, to parse results from the
+ * timeline setup sql query
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimelineSetupDataProcessor implements ResultSetProcessor<TimelineBean> {
+	/**
+	 * the result column timeband_description
+	 */
+	private static final String TIMEBAND_DESCRIPTION = "timeband_description";
+
+	/** the result column timeband_id */
+	private static final String TIMEBAND_ID = "timeband_id";
+
+	/** the result column timeband unit */
+	private static final String TIMEBAND_UNIT = "timeband_unit";
+
+	/** the parameters to pass in to the query */
+	private final Map<String, Object> params;
+
+	/**
+	 * public constructor
+	 */
+	public TimelineSetupDataProcessor() {
+		params = new HashMap<String, Object>();
+	}
+
+	public Map<String, Object> getParameters() {
+		return params;
+
+	}
+
+	public Query getQuery() {
+		return QueryImpl.GET_TIMELINE_SETUP_DATA;
+	}
+
+	public List<TimelineBean> process(final ResultSet rs) throws MalformedStepQueryException,
+			ConfigNotLoadedException, SQLException {
+		final List<TimelineBean> timelines = new ArrayList<TimelineBean>();
+
+		while (rs.next()) {
+			final TimelineBean bean = new TimelineBean();
+			bean.setTimelineId(rs.getInt(TIMEBAND_ID));
+			bean.setTimelineDescription(rs.getString(TIMEBAND_DESCRIPTION));
+			bean.setUnit(rs.getString(TIMEBAND_UNIT));
+			timelines.add(bean);
+		}
+		return timelines;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/CustomDispatchServiceServlet.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/CustomDispatchServiceServlet.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/CustomDispatchServiceServlet.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,47 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import net.customware.gwt.dispatch.server.Dispatch;
+import net.customware.gwt.dispatch.server.service.DispatchServiceServlet;
+
+import org.apache.commons.logging.Log;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+/**
+ * Step dispatch servlet to use for the dispatchin of queries
+ * 
+ * @author CJBurrell
+ * 
+ */
+ at Singleton
+public class CustomDispatchServiceServlet extends DispatchServiceServlet {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -6063357416925075136L;
+
+	/**
+	 * default logger
+	 */
+	private final Log logger;
+
+	/**
+	 * normal constructor
+	 * 
+	 * @param dispatch dispath object
+	 * @param logger logger to be provided
+	 */
+	@Inject
+	public CustomDispatchServiceServlet(final Dispatch dispatch, final Log logger) {
+		super(dispatch);
+		this.logger = logger;
+	};
+
+	@Override
+	protected void doUnexpectedFailure(final Throwable e) {
+		logger.error("An unexpected error happened on the bridge between server and client", e);
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/DispatchServletModule.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/DispatchServletModule.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/DispatchServletModule.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,20 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import com.google.inject.servlet.ServletModule;
+
+/**
+ * Servlet module for the Jetty/Tomcat server
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class DispatchServletModule extends ServletModule {
+
+	@Override
+	public void configureServlets() {
+		// NOTE: the servlet context will probably need changing
+
+		serve("/step/dispatch").with(CustomDispatchServiceServlet.class);
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/LogProvider.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/LogProvider.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/LogProvider.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,43 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.impl.Log4JLogger;
+
+import com.google.inject.Provider;
+import com.google.inject.Singleton;
+
+/**
+ * A Gin provider for logging purposes.
+ * 
+ * @author CJBurrell
+ * 
+ */
+ at Singleton
+public class LogProvider implements Provider<Log> {
+	// enforce singleton to allow static methods to get to the same log
+	/**
+	 * TODO: there should be a logger per class really. All appending to the
+	 * same file, but so that we can turn them on and off
+	 * 
+	 */
+	private static Log logger = new Log4JLogger("step.jetty");
+
+	/**
+	 * The static equivalent of the above, so that static contexts can log as
+	 * well
+	 * 
+	 * @return the log to use
+	 */
+	public static Log getLogger() {
+		return logger;
+	}
+
+	/**
+	 * The instantiated log to be returned
+	 * 
+	 * @return the Log file to be used
+	 */
+	public Log get() {
+		return logger;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/MyGuiceServletConfig.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/MyGuiceServletConfig.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/MyGuiceServletConfig.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,19 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.servlet.GuiceServletContextListener;
+
+/**
+ * The servlet configuraiton for Guice, which creates an injector
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class MyGuiceServletConfig extends GuiceServletContextListener {
+
+	@Override
+	protected Injector getInjector() {
+		return Guice.createInjector(new ServerModule(), new DispatchServletModule());
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/ServerModule.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/ServerModule.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/guice/ServerModule.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,37 @@
+package com.tyndalehouse.step.web.server.guice;
+
+import net.customware.gwt.dispatch.server.guice.ActionHandlerModule;
+
+import org.apache.commons.logging.Log;
+
+import com.google.inject.Singleton;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunnerImpl;
+import com.tyndalehouse.step.web.server.handler.GetAvailableBibleVersionsHandler;
+import com.tyndalehouse.step.web.server.handler.GetBibleBooksHandler;
+import com.tyndalehouse.step.web.server.handler.GetCurrentBibleTextHandler;
+import com.tyndalehouse.step.web.server.handler.GetDictionaryDefinitionHandler;
+import com.tyndalehouse.step.web.server.handler.GetEventsForDateRangeHandler;
+import com.tyndalehouse.step.web.server.handler.GetTimelineOriginForScriptureHandler;
+import com.tyndalehouse.step.web.server.handler.GetTimelineUISetupHandler;
+
+/**
+ * Module which binds the handlers and configurations
+ * 
+ */
+public class ServerModule extends ActionHandlerModule {
+
+	@Override
+	protected void configureHandlers() {
+		bindHandler(GetAvailableBibleVersionsHandler.class);
+		bind(Log.class).toProvider(LogProvider.class).in(Singleton.class);
+		bindHandler(GetBibleBooksHandler.class);
+		bindHandler(GetCurrentBibleTextHandler.class);
+		bindHandler(GetEventsForDateRangeHandler.class);
+		bindHandler(GetTimelineUISetupHandler.class);
+		bindHandler(GetTimelineOriginForScriptureHandler.class);
+		bindHandler(GetDictionaryDefinitionHandler.class);
+
+		bind(StepQueryRunner.class).to(StepQueryRunnerImpl.class).in(Singleton.class);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetAvailableBibleVersionsHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetAvailableBibleVersionsHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetAvailableBibleVersionsHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,63 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.logging.Log;
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookCategory;
+import org.crosswire.jsword.book.Books;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.shared.command.GetAvailableBibleVersionsCommand;
+import com.tyndalehouse.step.web.shared.result.GetAvailableBibleVersionsResult;
+
+/**
+ * Command handler returning all available bible versions
+ * 
+ * @author CJBurrell TODO: add logging to this class
+ */
+public class GetAvailableBibleVersionsHandler extends
+	AbstractStepHandler<GetAvailableBibleVersionsCommand, GetAvailableBibleVersionsResult> {
+	/**
+	 * Default logger
+	 */
+	private final Log logger;
+
+	/**
+	 * normal constructor
+	 * 
+	 * @param logger provided by Gin
+	 */
+	@Inject
+	public GetAvailableBibleVersionsHandler(final Log logger) {
+		this.logger = logger;
+	}
+
+	public GetAvailableBibleVersionsResult execute(final GetAvailableBibleVersionsCommand cmd,
+		final ExecutionContext arg1) throws ActionException {
+		// TODO: add handling of different types of book: bibles, commentaries,
+		// versions, etc.
+		@SuppressWarnings("unchecked")
+		final List<Book> books = Books.installed().getBooks();
+		final SortedMap<String, String> map = new TreeMap<String, String>();
+		for (final Book b : books) {
+			if (b.getBookCategory() == BookCategory.BIBLE) {
+				map.put(b.getInitials(), b.getName());
+			}
+		}
+		return new GetAvailableBibleVersionsResult(map);
+	}
+
+	public void rollback(final GetAvailableBibleVersionsCommand arg0,
+		final GetAvailableBibleVersionsResult arg1, final ExecutionContext arg2)
+		throws ActionException {
+		logger.error("Rolling back GetAvailableBibleVersions");
+
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetBibleBooksHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetBibleBooksHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetBibleBooksHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,70 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.ArrayList;
+import java.util.Locale;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.crosswire.jsword.passage.NoSuchVerseException;
+import org.crosswire.jsword.versification.BibleInfo;
+import org.crosswire.jsword.versification.BibleNames;
+import org.crosswire.jsword.versification.BookName;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.shared.command.GetBibleBooksCommand;
+import com.tyndalehouse.step.web.shared.result.GetBibleBooksCommandResult;
+
+/**
+ * Command handler for retrieving the different names of the books in a
+ * particular version TODO: only currently works for KJV
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetBibleBooksHandler extends
+	AbstractStepHandler<GetBibleBooksCommand, GetBibleBooksCommandResult> {
+	/**
+	 * public constructor
+	 */
+	@Inject
+	public GetBibleBooksHandler() {
+	}
+
+
+	public GetBibleBooksCommandResult execute(final GetBibleBooksCommand command,
+		final ExecutionContext arg1) throws ActionException {
+
+		getLogger().debug("GetBibleBooksCommandResult has been called...");
+
+		// TODO: on start up, we should check a whole load of things: jsword
+		// installed, database can be started, database has got data
+
+		// find selection of books and then add stuff to the suggestbox.
+		final ArrayList<String> suggestions = new ArrayList<String>();
+
+		// http://www.crosswire.org/jsword/java2html/org/crosswire/jsword/bridge/BibleScope.java.html
+		// TODO: currently based on KJV versification, when better to base it on
+		// preferred version
+		// of the bible...
+		try {
+			final int booksInBible = BibleInfo.booksInBible();
+			BookName bn;
+			final BibleNames all = new BibleNames(Locale.getDefault());
+			for (int ii = 1; ii <= booksInBible; ii++) {
+				bn = all.getName(ii);
+				suggestions.add(bn.getPreferredName());
+			}
+		} catch (final NoSuchVerseException e) {
+			getLogger().error("Failed to generate list of bible books", e);
+		}
+
+		return new GetBibleBooksCommandResult(suggestions);
+	}
+
+	public void rollback(final GetBibleBooksCommand arg0, final GetBibleBooksCommandResult arg1,
+		final ExecutionContext context) throws ActionException {
+
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetCurrentBibleTextHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetCurrentBibleTextHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetCurrentBibleTextHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,514 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.transform.TransformerException;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.lang.StringUtils;
+import org.crosswire.common.util.Reporter;
+import org.crosswire.common.xml.SAXEventProvider;
+import org.crosswire.common.xml.TransformingSAXEventProvider;
+import org.crosswire.common.xml.XMLUtil;
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookData;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.BookMetaData;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.book.OSISUtil;
+import org.crosswire.jsword.passage.NoSuchKeyException;
+import org.jdom.Attribute;
+import org.jdom.Content;
+import org.jdom.Element;
+import org.jdom.Text;
+import org.jdom.filter.Filter;
+import org.xml.sax.SAXException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.common.JSwordConstants;
+import com.tyndalehouse.step.web.server.handler.util.passage.StrongMorphMap;
+import com.tyndalehouse.step.web.server.jsword.ConfigurableHTMLConverter;
+import com.tyndalehouse.step.web.shared.command.GetCurrentBibleTextCommand;
+import com.tyndalehouse.step.web.shared.result.GetCurrentBibleTextResult;
+import com.tyndalehouse.step.web.shared.scripture.Milestone;
+import com.tyndalehouse.step.web.shared.scripture.Note;
+import com.tyndalehouse.step.web.shared.scripture.OSISConstants;
+import com.tyndalehouse.step.web.shared.scripture.Passage;
+import com.tyndalehouse.step.web.shared.scripture.TextualElement;
+import com.tyndalehouse.step.web.shared.scripture.Title;
+import com.tyndalehouse.step.web.shared.scripture.TransChange;
+import com.tyndalehouse.step.web.shared.scripture.Verse;
+import com.tyndalehouse.step.web.shared.scripture.VerseContent;
+import com.tyndalehouse.step.web.shared.scripture.Word;
+
+/**
+ * Command handler returning a portion of scripture in different formats
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetCurrentBibleTextHandler extends
+	AbstractStepHandler<GetCurrentBibleTextCommand, GetCurrentBibleTextResult> {
+
+	/**
+	 * default constructor with the getLogger
+	 * 
+	 */
+	@Inject
+	public GetCurrentBibleTextHandler() {
+
+	}
+
+
+	public GetCurrentBibleTextResult execute(final GetCurrentBibleTextCommand command,
+		final ExecutionContext arg1) throws ActionException {
+		final String version = command.getVersion();
+		final String reference = command.getReference();
+
+		// check information has been passed in
+		// TODO: ensure error handling is handled properly
+		if (StringUtils.isEmpty(version)) {
+			throw new ActionException("Version was not provided");
+		}
+		if (StringUtils.isEmpty(reference)) {
+			throw new ActionException("Reference was not provided");
+		}
+
+		final GetCurrentBibleTextResult result = new GetCurrentBibleTextResult();
+
+		final BookData data = getBookData(version, reference);
+
+		switch (command.getTypeOfLookup()) {
+		case CLASSIC_INTERLINEAR:
+			addClassicInterlinear(result.getPassage(), reference);
+			break;
+		case LOGICAL:
+			addLogicalLookup(result, data);
+			break;
+		case PLAIN_TEXT:
+			try {
+				result.setPassageText(OSISUtil.getCanonicalText(data.getOsis()));
+			} catch (final BookException e) {
+				throw new ActionException("Unable to get simple canonical text from book", e);
+			}
+			break;
+		case REVERSE_INTERLINEAR:
+			addLogicalLookup(result, data);
+			addReverseInterlinear(result.getPassage(), reference);
+			break;
+		case XSLT:
+			result.setXsltedText(doXslt(data));
+			break;
+		default:
+			// do nothing since nothing was requested
+			break;
+		}
+		return result;
+	}
+
+	public void rollback(final GetCurrentBibleTextCommand arg0,
+		final GetCurrentBibleTextResult arg1, final ExecutionContext arg2) throws ActionException {
+		getLogger().error("Get Current Bible Text rolling back");
+
+	}
+
+	/**
+	 * does a classic interlinear and populates the Passage
+	 * 
+	 * @param p the logical passage to be populated
+	 * @param reference the reference
+	 */
+	private void addClassicInterlinear(final Passage p, final String reference) {
+		// TODO: feature
+		// identify the hebrew/greek version of the text, and get book data for
+		// the appropriate version
+		// final VerseRange vrf = VerseRangeFactory.fromString(reference);
+		// TODO updgrade to latest jsword version
+
+		// VerseRange.remainder(vrf, null);
+
+		// getBookData(version, reference);
+	}
+
+	/**
+	 * adds a logical lookup to the result objet
+	 * 
+	 * @param result the result object to populate
+	 * @param data the data to base the lookup upon
+	 * @throws ActionException an exception thrown if the parsing or lookup goes
+	 *             bad
+	 */
+	private void addLogicalLookup(final GetCurrentBibleTextResult result, final BookData data)
+		throws ActionException {
+		final Passage p = parseForGwt(data);
+		result.setPassage(p);
+	}
+
+	/**
+	 * doing a reverse interlinear
+	 * 
+	 * @param translatedText the passage as looked up in an non-original version
+	 * @param reference the reference of the text so we can add the original
+	 *            text onto it
+	 * @throws ActionException action exception thrown during execution of the
+	 *             reverse interlinear process
+	 */
+	private void addReverseInterlinear(final Passage translatedText, final String reference)
+		throws ActionException {
+		// first lookup passage from LXX or TODO user chosen version
+		// TODO: cope with Hebrew
+		String versionToUse;
+		StrongMorphMap strongMorphMap;
+
+		if (isGreek(translatedText)) {
+			versionToUse = JSwordConstants.DEFAULT_GREEK_INTERLINEAR_TEXT;
+		} else {
+			// assume Hebrew
+			versionToUse = JSwordConstants.DEFAULT_HEBREW_INTERLINEAR_TEXT;
+		}
+
+		// TODO: we need to do something different here,
+		// we don't need to parse through the whole lot, and probably JDom
+		// allows us to use filters to get all children of a certain kind,
+		// we want to end up with a keyed map, looking like [strong, morph?] ->
+		// word
+		try {
+			strongMorphMap = getStrongMorphMap(getBookData(versionToUse, reference));
+		} catch (final BookException e) {
+			throw new ActionException("Unable to lookup source text and parse to StrongMorphMap", e);
+		}
+
+		mergePassages(translatedText, strongMorphMap);
+	}
+
+	/**
+	 * parsing a milestone into a logical element
+	 * 
+	 * @param verseContent the Content on which to append the logical element
+	 * @param v the verse
+	 */
+	private void doMilestone(final Element verseContent, final Verse v) {
+		final Milestone m = new Milestone();
+		m.setMarker(verseContent.getAttributeValue(OSISConstants.MARKER));
+		m.setType(verseContent.getAttributeValue(OSISUtil.OSIS_ATTR_TYPE));
+		v.addTextualElement(m);
+	}
+
+	/**
+	 * parsing a note into a logical element
+	 * 
+	 * @param verseContent the Content on which to append the logical element
+	 * @param v the verse
+	 */
+	private void doNote(final Element verseContent, final Verse v) {
+		final Note n = new Note();
+		n.setType(verseContent.getAttributeValue(OSISUtil.OSIS_ATTR_TYPE));
+		n.setText(verseContent.getText());
+		v.addTextualElement(n);
+	}
+
+	/**
+	 * parses a title
+	 * 
+	 * @param titleElement the xml title element
+	 * @param passage the passage to be parsed into
+	 */
+	private void doTitle(final Element titleElement, final Passage passage) {
+		final Title title = new Title();
+		title.setType(titleElement.getAttributeValue(OSISUtil.OSIS_ATTR_TYPE));
+		title.setText(titleElement.getText());
+		passage.addPassageElement(title);
+	}
+
+	/**
+	 * parses a TransChange element
+	 * 
+	 * @param verseContent the trans change element
+	 * @param v the verse to be parsed into
+	 */
+	private void doTransChange(final Element verseContent, final Verse v) {
+		final TransChange t = new TransChange();
+		t.setType(verseContent.getAttributeValue(OSISUtil.OSIS_ATTR_TYPE));
+		t.setText(verseContent.getText());
+		v.addTextualElement(t);
+	}
+
+	/**
+	 * parses a verse xml element
+	 * 
+	 * @param e the verse element
+	 * @param passage the passage to be parsed into
+	 */
+	private void doVerse(final Element e, final Passage passage) {
+		final List<Content> verseWords = e.getContent();
+		final Verse v = new Verse();
+		v.setOsisID(e.getAttributeValue(OSISUtil.OSIS_ATTR_OSISID));
+		passage.addPassageElement(v);
+
+		for (final Content c : verseWords) {
+			if (c instanceof Element) {
+				final Element verseContent = (Element) c;
+				final String tagName = verseContent.getName();
+				if (tagName.equals(OSISUtil.OSIS_ELEMENT_W)) {
+					doWord(verseContent, v);
+				} else if (tagName.equals(OSISUtil.OSIS_ELEMENT_NOTE)) {
+					doNote(verseContent, v);
+				} else if (tagName.equals(OSISConstants.MILESTONE)) {
+					doMilestone(verseContent, v);
+				} else if (tagName.equals(OSISConstants.TRANS_CHANGE)) {
+					doTransChange(verseContent, v);
+				} else {
+					getLogger().warn(String.format("Unexpected element %s", tagName));
+				}
+			} else if (c instanceof Text) {
+				final Text textElement = (Text) c;
+				final com.tyndalehouse.step.web.shared.scripture.Text t = new com.tyndalehouse.step.web.shared.scripture.Text(
+					textElement.getText());
+				v.addTextualElement(t);
+			} else {
+				// we're in trouble
+				getLogger().warn("Content c is not recognised: " + c.getClass().getCanonicalName());
+			}
+		}
+	}
+
+	/**
+	 * processes a word from the bible text passed in as XML
+	 * 
+	 * @param verseContent verseContent in XML
+	 * @param v the object version of this word
+	 */
+	private void doWord(final Element verseContent, final Verse v) {
+		final Word w = new Word();
+
+		final String lemmas = verseContent.getAttributeValue(OSISUtil.ATTRIBUTE_W_LEMMA);
+		final String morphs = verseContent.getAttributeValue(OSISUtil.ATTRIBUTE_W_MORPH);
+
+		// TODO: make a constant
+		if (lemmas != null) {
+			w.addLemmas(lemmas.split(" "));
+		}
+		if (morphs != null) {
+			w.addMorphs(morphs.split(" "));
+		}
+		w.setText(verseContent.getText());
+		v.addTextualElement(w);
+	}
+
+	/**
+	 * does an xslt transformation on some OSIS text
+	 * 
+	 * @param data data of the book to use and the key in the book.
+	 * @return the passage xslted version
+	 */
+	private String doXslt(final BookData data) {
+		if (data == null) {
+			return "";
+		}
+
+		// Make sure Hebrew displays from Right to Left
+		final BookMetaData bmd = data.getFirstBook().getBookMetaData();
+		if (bmd == null) {
+			return "";
+		}
+
+		try {
+			final SAXEventProvider osissep = data.getSAXEventProvider();
+
+			final TransformingSAXEventProvider htmlsep = (TransformingSAXEventProvider) new ConfigurableHTMLConverter()
+				.convert(osissep);
+			final String text = XMLUtil.writeToString(htmlsep);
+			return text;
+		} catch (final SAXException e) {
+			Reporter.informUser(this, e);
+		} catch (final BookException e) {
+			Reporter.informUser(this, e);
+		} catch (final TransformerException e) {
+			Reporter.informUser(this, e);
+		}
+		return "";
+	}
+
+	/**
+	 * returns the book data using the JSword API
+	 * 
+	 * @param version version to be looked up
+	 * @param reference reference of the passage
+	 * @return the JSword BookData object
+	 * @throws ActionException an exception should an problem happen
+	 */
+	private BookData getBookData(final String version, final String reference)
+		throws ActionException {
+		try {
+			final Book currentBook = Books.installed().getBook(version);
+			final BookData data = new BookData(currentBook, currentBook.getKey(reference));
+			return data;
+		} catch (final NoSuchKeyException e) {
+			getLogger().error("An error occurred looking up the passage", e);
+			throw new ActionException(e);
+		}
+	}
+
+	/**
+	 * given a book data (referencing a biblical reference + a book), retrieves
+	 * the morphs and the Strong numbers (lemmas) in the passage to help in the
+	 * interlinear processing
+	 * 
+	 * @param bookData the bookData from JSword specialised for the reference
+	 *            and bible book
+	 * @return a map of strong numbers and morphs
+	 * @throws BookException an exception occuring during parsing of the OSIS
+	 *             XML
+	 */
+	@SuppressWarnings("unchecked")
+	private StrongMorphMap getStrongMorphMap(final BookData bookData) throws BookException {
+		final Element osis = bookData.getOsisFragment();
+		final StrongMorphMap strongMorphMap = new StrongMorphMap();
+		final Iterator<Element> it = osis.getDescendants(new Filter() {
+			/**
+			 * serial id
+			 */
+			private static final long serialVersionUID = 4171956787222841308L;
+
+			public boolean matches(final Object obj) {
+				return obj instanceof Element
+					&& ((Element) obj).getName().equals(OSISUtil.OSIS_ELEMENT_W);
+			}
+
+		});
+
+		while (it.hasNext()) {
+			final Element word = it.next();
+			final Attribute lemmaAttribute = word.getAttribute(OSISUtil.ATTRIBUTE_W_LEMMA);
+			final Attribute morphAttribute = word.getAttribute(OSISUtil.ATTRIBUTE_W_MORPH);
+
+			if (lemmaAttribute != null) {
+				if (morphAttribute != null) {
+					strongMorphMap.addWord(lemmaAttribute.getValue(), morphAttribute.getValue(),
+						word.getValue());
+				} else {
+					strongMorphMap.addWord(lemmaAttribute.getValue(), word.getValue());
+				}
+			}
+		}
+
+		return strongMorphMap;
+	}
+
+	/**
+	 * Look at the first word with a lemma and return lemma[0] == 'G'
+	 * 
+	 * @param p passage to be looked up
+	 * @return true if the word with the first lemma is in Greek
+	 */
+	private boolean isGreek(final Passage p) {
+		for (final VerseContent vc : p.getVerseContent()) {
+			if (vc instanceof Verse) {
+				final Verse v = (Verse) vc;
+				for (final TextualElement te : v.getVerseContent()) {
+					if (te instanceof Word) {
+						final Word w = (Word) te;
+						if (w.getLemma() != null) {
+							return w.getLemma().get(0).charAt(
+								JSwordConstants.STRONG_PATTERN_START.length()) == JSwordConstants.STRONG_GREEK_MARKER;
+						}
+					}
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * Iterates through the master passage and incorporates into it, the text
+	 * given and mapped in the strongMorphMap
+	 * 
+	 * @param masterPassage the passage to be enriched
+	 * @param strongMorphMap the map containing the links.
+	 */
+	// TODO: tidy up all the different iterator approaches, widely using
+	// instanceof
+	private void mergePassages(final Passage masterPassage, final StrongMorphMap strongMorphMap) {
+		// iterate through the masterPassage, and lookup the strong morph map
+		final List<VerseContent> verseContent = masterPassage.getVerseContent();
+		List<String> lemma, morph;
+		for (final VerseContent vc : verseContent) {
+			if (vc instanceof Verse) {
+				final Verse v = (Verse) vc;
+				for (final TextualElement te : v.getVerseContent()) {
+					if (te instanceof Word) {
+						final Word w = (Word) te;
+
+						// we have several lemmas for each word, and therefore,
+						// we need to loop round them
+						lemma = w.getLemma();
+						morph = w.getMorph();
+
+						final StringBuffer alternativeWording = new StringBuffer(64);
+
+						// we iterate through each lemma, knowing that we may
+						// not have morphs at all (Hebrew text)
+						// we cannot use the morph without the lemma, although
+						// TODO: check what we're supposed to do
+						// when we only have one morphology for several lemmas
+						// always 0 or equal to number of lemmas
+						for (int ii = 0; ii < lemma.size(); ii++) {
+							final String l = lemma.get(ii);
+							final String m = ii < morph.size() ? morph.get(ii) : null;
+							final String text = strongMorphMap.get(l, m);
+							if (text != null) {
+								alternativeWording.append(text);
+								alternativeWording.append(' ');
+							}
+							w.setAlternativeWord(alternativeWording.toString());
+						}
+					}
+				}
+			}
+		}
+	}
+
+	/**
+	 * parsing an element
+	 * 
+	 * @param data the book data to used as a basis for parsing
+	 * @return the passage once parsed, et al.
+	 * @throws ActionException an exception to bubble up to the web UI
+	 */
+	@SuppressWarnings("unchecked")
+	// TODO: upgrade to latest JSword version for generics
+	private Passage parseForGwt(final BookData data) throws ActionException {
+		Element osisFragment;
+		try {
+			osisFragment = data.getOsisFragment();
+		} catch (final BookException e1) {
+			throw new ActionException("Unable to get OSIS Fragment from selected version");
+		}
+
+		final List<Content> l = osisFragment.getContent();
+		final Passage passage = new Passage();
+
+		// First level can be title or verse
+		for (final Content el : l) {
+			// check whether we've just got text, or a verse or something
+			if (el instanceof Element) {
+				final Element e = (Element) el;
+
+				if (e.getName().equals(OSISUtil.OSIS_ELEMENT_TITLE)) {
+					doTitle(e, passage);
+				} else if (e.getName().equals(OSISUtil.OSIS_ELEMENT_VERSE)) {
+					doVerse(e, passage);
+				}
+			} else {
+				// this shouldn't happen
+				getLogger().warn("Unexpected text while parsing gwt");
+			}
+		}
+
+		return passage;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetDictionaryDefinitionHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetDictionaryDefinitionHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetDictionaryDefinitionHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,175 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.List;
+
+import javax.xml.transform.TransformerException;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.apache.commons.lang.StringUtils;
+import org.crosswire.common.util.Reporter;
+import org.crosswire.common.xml.SAXEventProvider;
+import org.crosswire.common.xml.TransformingSAXEventProvider;
+import org.crosswire.common.xml.XMLUtil;
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookData;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.passage.NoSuchKeyException;
+import org.jdom.Element;
+import org.xml.sax.SAXException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.common.JSwordConstants;
+import com.tyndalehouse.step.web.server.jsword.ConfigurableHTMLConverter;
+import com.tyndalehouse.step.web.shared.command.GetDictionaryDefinitionCommand;
+import com.tyndalehouse.step.web.shared.result.GetDictionaryDefinitionResult;
+
+/**
+ * Looks up the dictionary definition in a JSword module and returns it to the
+ * client
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetDictionaryDefinitionHandler extends
+	AbstractStepHandler<GetDictionaryDefinitionCommand, GetDictionaryDefinitionResult> {
+
+	/**
+	 * The dictionary definition handler's constructor
+	 */
+	@Inject
+	public GetDictionaryDefinitionHandler() {
+	}
+
+
+
+	public GetDictionaryDefinitionResult execute(final GetDictionaryDefinitionCommand command,
+		final ExecutionContext arg1) throws ActionException {
+		final List<String> referenceList = command.getLookupReferencce();
+		final GetDictionaryDefinitionResult result = new GetDictionaryDefinitionResult();
+
+		final StringBuffer definitions = new StringBuffer(300);
+		// for each definition: TODO : probably want to pass back a list of
+		// definitions, and tab them
+		// on the popup!
+		for (final String reference : referenceList) {
+			definitions.append(lookUpDefinition(reference));
+			definitions.append("<hr />");
+
+		}
+		result.setDefinition(definitions.toString());
+		return result;
+	}
+
+	
+	public void rollback(final GetDictionaryDefinitionCommand arg0,
+		final GetDictionaryDefinitionResult arg1, final ExecutionContext arg2)
+		throws ActionException {
+		getLogger().error("Get Dictionary definition Text rolling back");
+
+	}
+
+	/**
+	 * does a simple xslt transformation to show the definition on the screen
+	 * 
+	 * @param data data to be shown
+	 * @param osisFragment osisFragment to transform
+	 * @return the xslted definition ready to be displayed on the user's screen
+	 */
+	private String doXslt(final BookData data, final Element osisFragment) {
+		if (data == null) {
+			return "";
+		}
+
+		try {
+			final SAXEventProvider osissep = data.getSAXEventProvider();
+			// TODO: do some work on the XSLT definition
+			final TransformingSAXEventProvider htmlsep = (TransformingSAXEventProvider) new ConfigurableHTMLConverter()
+				.convert(osissep);
+			final String text = XMLUtil.writeToString(htmlsep);
+			return text;
+		} catch (final SAXException e) {
+			Reporter.informUser(this, e);
+		} catch (final BookException e) {
+			Reporter.informUser(this, e);
+		} catch (final TransformerException e) {
+			Reporter.informUser(this, e);
+		}
+		return "";
+	}
+
+	/**
+	 * dependant on the reference, we return a different module to lookup the
+	 * definition. For e.g. we use a Greek dictionary to lookup a reference
+	 * starting strong:Gxxxxx
+	 * 
+	 * @param reference reference to be looked up
+	 * @return the module initials to use for the dictionary lookup
+	 * @throws ActionException an exception to be thrown if the reference is not
+	 *             recognised
+	 */
+	private String getInitialsFromReference(final String reference) throws ActionException {
+		if (reference.toLowerCase().startsWith(JSwordConstants.STRONG_PATTERN_START)) {
+			final int charPosition = JSwordConstants.STRONG_PATTERN_START.length();
+			if (reference.charAt(charPosition) == JSwordConstants.STRONG_HEBREW_MARKER) {
+				return JSwordConstants.STRONG_HEBREW_DICTIONARY_INITIALS;
+			} else if (reference.charAt(charPosition) == JSwordConstants.STRONG_GREEK_MARKER) {
+				return JSwordConstants.STRONG_GREEK_DICTIONARY_INITIALS;
+			}
+			// continuing will throw exception
+		}
+		throw new ActionException(String.format("Dictionary reference not recognised: %s",
+			reference));
+	}
+
+	/**
+	 * returns the actual reference, removing the strong pattern + first
+	 * initial. For e.g. removes strong:H from "strong:H00002"
+	 * 
+	 * @param reference reference to parse
+	 * @return the key in the dictionary to be used for lookup purposes
+	 * @throws ActionException the action exception
+	 */
+	private String getLookupKeyFromReference(final String reference) throws ActionException {
+		if (reference.toLowerCase().startsWith(JSwordConstants.STRONG_PATTERN_START)) {
+			// remove strong:H or strong:G
+			return reference.substring(JSwordConstants.STRONG_PATTERN_START.length() + 1);
+		}
+		throw new ActionException(String.format("Lookup key not recognised: %s", reference));
+	}
+
+	/**
+	 * Looks up a definition given a reference in the default JSword module
+	 * 
+	 * @param reference reference, for e.g. a Strong number
+	 * @return the definition
+	 * @throws ActionException an exception occurring if the reference is
+	 *             invalid
+	 */
+	private String lookUpDefinition(final String reference) throws ActionException {
+		if (StringUtils.isEmpty(reference)) {
+			throw new ActionException("Reference was not provided");
+		}
+		getLogger().error("definition lookup command");
+		final String initials = getInitialsFromReference(reference);
+		final String lookupKey = getLookupKeyFromReference(reference);
+
+		try {
+			// TODO: ensure a lookup key exists!
+			// TODO: make a common adapter api to access JSword
+			final Book currentBook = Books.installed().getBook(initials);
+			final BookData data = new BookData(currentBook, currentBook.getKey(lookupKey));
+			final String xsltedDefinition = doXslt(data, data.getOsisFragment());
+			return xsltedDefinition;
+		} catch (final NoSuchKeyException e) {
+			getLogger().error("An error occurred looking up the passage", e);
+			throw new ActionException(e);
+		} catch (final BookException e) {
+			getLogger().error("A book exception has occurred whilte looking up the passage", e);
+			throw new ActionException(e);
+		}
+	}
+}

Added: 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	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetEventsForDateRangeHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,104 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.server.db.framework.UnableToRunQueryException;
+import com.tyndalehouse.step.web.server.db.timeline.TimeBandVisibleDateProcessor;
+import com.tyndalehouse.step.web.shared.command.GetEventsForDateRangeCommand;
+import com.tyndalehouse.step.web.shared.common.timeline.TimeBandVisibleDate;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineEventBean;
+import com.tyndalehouse.step.web.shared.result.GetEventsForDateRangeResult;
+
+/**
+ * Command that gets relevant events on a date range. Currently this executes
+ * multiple queries against the database
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetEventsForDateRangeHandler extends
+	AbstractStepHandler<GetEventsForDateRangeCommand, GetEventsForDateRangeResult> {
+
+	/**
+	 * The step query runner to run queries against the database
+	 */
+	private final StepQueryRunner queryRunner;
+
+	/**
+	 * public constructor for this handler
+	 * 
+	 * @param queryRunner the query runner object to use for executing the query
+	 */
+	@Inject
+	public GetEventsForDateRangeHandler(final StepQueryRunner queryRunner) {
+		this.queryRunner = queryRunner;
+	}
+
+
+	// 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(final GetEventsForDateRangeCommand event,
+		final ExecutionContext arg1) throws ActionException {
+		final GetEventsForDateRangeResult result = new GetEventsForDateRangeResult();
+		final List<TimeBandVisibleDate> timebands = event.getVisbleDates();
+		try {
+			for (final TimeBandVisibleDate tvd : timebands) {
+				List<TimelineEventBean> events;
+				events = queryRunner.run(new TimeBandVisibleDateProcessor(tvd.getMinDate(), tvd
+					.getMaxDate(), tvd.getTimebandId()));
+				result.getEvents().addAll(events);
+			}
+		} catch (final UnableToRunQueryException e) {
+			getLogger().error(
+				"An error occured while trying to retrieve new events from the datbase", e);
+			throw new ActionException(e);
+		}
+
+		logEventsRetrieved(result.getEvents());
+		return result;
+	}
+
+	public void rollback(final GetEventsForDateRangeCommand arg0,
+		final GetEventsForDateRangeResult arg1, final ExecutionContext arg2) throws ActionException {
+
+	}
+
+	/**
+	 * Logs which events have been retrieved in trace mode
+	 * 
+	 * @param events events to be traced
+	 */
+	private void logEventsRetrieved(final List<TimelineEventBean> events) {
+		final SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy G");
+
+		if (getLogger().isTraceEnabled()) {
+			for (final TimelineEventBean teb : events) {
+				if (teb.getFromDate() != null && teb.getToDate() != null) {
+					getLogger().trace(
+						String.format("returning: %s %s-%s (tb_id: %d)", teb.getName(), sdf
+							.format(new Date(teb.getFromDate())), sdf.format(new Date(teb
+							.getToDate())), teb.getTimelineId()));
+
+				} else if (teb.getFromDate() != null) {
+					getLogger().trace(
+						String.format("returning: %s %s (tb_id: %d)", teb.getName(), sdf
+							.format(new Date(teb.getFromDate())), teb.getTimelineId()));
+				} else {
+					getLogger().trace(
+						String.format("returning: %s (tb_id: %d)", teb.getName(), teb
+							.getTimelineId()));
+				}
+			}
+		}
+		getLogger().trace(String.format("Returning %d events to the client", events.size()));
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetLocationsHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetLocationsHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetLocationsHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,51 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.shared.command.GetLocationsCommand;
+import com.tyndalehouse.step.web.shared.result.GetLocationsResult;
+
+/**
+ * The GetLocations command gets geographical locations from the server
+ * datasources and sends them back to the client
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetLocationsHandler extends
+	AbstractStepHandler<GetLocationsCommand, GetLocationsResult> {
+
+	/**
+	 * Default constructor
+	 * 
+	 * @param queryRunner a query runner
+	 */
+	@Inject
+	public GetLocationsHandler(final StepQueryRunner queryRunner) {
+//		this.queryRunner = queryRunner;
+	}
+
+
+	public GetLocationsResult execute(final GetLocationsCommand arg0, final ExecutionContext arg1)
+		throws ActionException {
+		// try {
+		// final List<GeoLoc> timelines = queryRunner.run(new
+		// TimelineSetupDataProcessor());
+		final GetLocationsResult r = new GetLocationsResult();
+		return r;
+		// } catch (final UnableToRunQueryException e) {
+		// getLogger().error("An error occured while loading the config for the query",
+		// e);
+		// throw new ActionException(e);
+		// }
+	}
+
+	public void rollback(final GetLocationsCommand arg0, final GetLocationsResult arg1,
+		final ExecutionContext arg2) throws ActionException {
+		getLogger().error("Get Locations Handler rolling back");
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineOriginForScriptureHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineOriginForScriptureHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineOriginForScriptureHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,121 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.List;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.crosswire.jsword.passage.Key;
+import org.crosswire.jsword.passage.KeyFactory;
+import org.crosswire.jsword.passage.NoSuchKeyException;
+import org.crosswire.jsword.passage.PassageKeyFactory;
+import org.crosswire.jsword.passage.RestrictionType;
+import org.crosswire.jsword.passage.RocketPassage;
+import org.crosswire.jsword.passage.VerseRange;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.db.framework.ResultSetProcessor;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.server.db.framework.UnableToRunQueryException;
+import com.tyndalehouse.step.web.server.db.timeline.TimelineOriginDbBean;
+import com.tyndalehouse.step.web.server.db.timeline.TimelineOriginProcessor;
+import com.tyndalehouse.step.web.shared.command.GetTimelineOriginForScriptureCommand;
+import com.tyndalehouse.step.web.shared.result.GetTimelineOriginForScriptureResult;
+
+/**
+ * returns the timeline origin, i.e the best (closest in time) event for a given
+ * verse range.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetTimelineOriginForScriptureHandler extends
+	AbstractStepHandler<GetTimelineOriginForScriptureCommand, GetTimelineOriginForScriptureResult> {
+	/**
+	 * The step query runner to run queries against the database
+	 */
+	private final StepQueryRunner queryRunner;
+
+	/**
+	 * constructor for this handler
+	 * 
+	 * @param queryRunner the query runner framework
+	 */
+	@Inject
+	public GetTimelineOriginForScriptureHandler(final StepQueryRunner queryRunner) {
+		this.queryRunner = queryRunner;
+	}
+
+
+	// 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 GetTimelineOriginForScriptureResult execute(
+		final GetTimelineOriginForScriptureCommand event, final ExecutionContext arg1)
+		throws ActionException {
+		try {
+			// TODO: this is bad - look at JSword to work out how to properly
+			// get the verserange out
+			final RocketPassage passage = (RocketPassage) resolveScriptureToVerseNumbers(event
+				.getScriptureReference());
+
+			if (passage.isEmpty()) {
+				getLogger().warn("No passage was requested");
+			} else {
+
+				// TODO: we're doing only the first range - ignoring others...
+				// What would we do with several ranges? Interesting question -
+				// perhaps we could use as min/max
+				final VerseRange range = passage.getRangeAt(0, RestrictionType.NONE);
+				final int startVerseNo = range.getStart().getOrdinal();
+				final int endVerseNo = range.getEnd().getOrdinal();
+
+				final ResultSetProcessor<TimelineOriginDbBean> originProcessor = new TimelineOriginProcessor(
+					startVerseNo, endVerseNo);
+
+				// TODO: should be able to ensure this is implied, rather having
+				// to cast directly
+				final List<TimelineOriginDbBean> originList = queryRunner.run(originProcessor);
+
+				if (originList.size() != 0) {
+					final TimelineOriginDbBean origin = originList.get(0);
+					return new GetTimelineOriginForScriptureResult(origin.getOrigin(), origin
+						.getUnit(), origin.getTimebandId());
+				} // else {
+				// // TODO: work out the nearest passage and redo this...
+				// }
+			}
+		} catch (final NoSuchKeyException e) {
+			getLogger().warn("Could not resolve verse number", e);
+			// TODO: return a proper exception and show error message on the UI
+			return new GetTimelineOriginForScriptureResult(true);
+		} catch (final UnableToRunQueryException e) {
+			getLogger().error("An error occured while loading the config for the query", e);
+			throw new ActionException(e);
+		}
+		return new GetTimelineOriginForScriptureResult(true);
+	}
+
+	public void rollback(final GetTimelineOriginForScriptureCommand arg0,
+		final GetTimelineOriginForScriptureResult arg1, final ExecutionContext arg2)
+		throws ActionException {
+
+	}
+
+	/**
+	 * resolves a string to a range of verses
+	 * 
+	 * @return the OSIS key to use to look up a particular scripture reference
+	 *         in a JSword module
+	 * @throws NoSuchKeyException thrown if the passed in reference cannot be
+	 *             parsed //TODO: make into seperate util classes
+	 */
+	private Key resolveScriptureToVerseNumbers(final String scriptureReference)
+		throws NoSuchKeyException {
+		final KeyFactory keyFactory = PassageKeyFactory.instance();
+		return keyFactory.getKey(scriptureReference);
+
+	}
+}

Added: 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	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/GetTimelineUISetupHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,66 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.List;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.server.db.framework.StepQueryRunner;
+import com.tyndalehouse.step.web.server.db.framework.UnableToRunQueryException;
+import com.tyndalehouse.step.web.server.db.timeline.TimelineSetupDataProcessor;
+import com.tyndalehouse.step.web.shared.command.GetTimelineUISetupCommand;
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineBean;
+import com.tyndalehouse.step.web.shared.result.GetTimelineUISetupResult;
+
+/**
+ * the timeline UI setup handler, which returns the initial set of data for the
+ * timeline module including the different bands, their recommended scales, etc.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetTimelineUISetupHandler extends
+	AbstractStepHandler<GetTimelineUISetupCommand, GetTimelineUISetupResult> {
+	/**
+	 * The step query runner to run queries against the database
+	 */
+	private final StepQueryRunner queryRunner;
+
+	/**
+	 * Default constructor
+	 * 
+	 * @param queryRunner a query runner
+	 */
+	@Inject
+	public GetTimelineUISetupHandler(final StepQueryRunner queryRunner) {
+		this.queryRunner = queryRunner;
+	}
+
+	// TODO: this can be cached quite succesfully on the server
+
+	public GetTimelineUISetupResult execute(final GetTimelineUISetupCommand cmd,
+		final ExecutionContext arg1) throws ActionException {
+		try {
+			final List<TimelineBean> timelines = queryRunner.run(new TimelineSetupDataProcessor());
+			final GetTimelineUISetupResult r = new GetTimelineUISetupResult();
+			r.setTimelines(timelines);
+
+			if (getLogger().isDebugEnabled()) {
+				getLogger().debug(
+					String.format("Returning %d timebands to the client.", timelines.size()));
+			}
+			return r;
+		} catch (final UnableToRunQueryException e) {
+			getLogger().error("An error occured while loading the config for the query", e);
+			throw new ActionException(e);
+		}
+	}
+
+	public void rollback(final GetTimelineUISetupCommand arg0, final GetTimelineUISetupResult arg1,
+		final ExecutionContext arg2) throws ActionException {
+		getLogger().error("Get Timeline UI Setup Handler rolling back");
+
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/InstallJswordModuleHandler.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/InstallJswordModuleHandler.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/InstallJswordModuleHandler.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,150 @@
+package com.tyndalehouse.step.web.server.handler;
+
+import java.util.Set;
+
+import net.customware.gwt.dispatch.server.ExecutionContext;
+import net.customware.gwt.dispatch.shared.ActionException;
+
+import org.crosswire.common.progress.JobManager;
+import org.crosswire.common.progress.Progress;
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.book.install.sword.HttpSwordInstaller;
+
+import com.google.inject.Inject;
+import com.tyndalehouse.step.web.server.common.AbstractStepHandler;
+import com.tyndalehouse.step.web.shared.command.InstallJswordModuleCommand;
+import com.tyndalehouse.step.web.shared.result.InstallJswordModuleResult;
+
+/**
+ * Handler that installs a JSword module (bible, etc.) on to the server (perhaps
+ * a localhost server)
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class InstallJswordModuleHandler extends
+	AbstractStepHandler<InstallJswordModuleCommand, InstallJswordModuleResult> {
+
+	// TODO: move the lookup to properties file
+	/**
+	 * proxy to use to access the internet from step
+	 */
+	private static final String PROXY_HOST = "step.proxy.host";
+
+	/**
+	 * proxy port to use for accessing the internet form step
+	 */
+	private static final String PROXY_PORT = "step.proxy.port";
+
+	/**
+	 * the time to wait for installer to kick in, so that we can then wait for
+	 * it
+	 */
+	private static final int WAIT_TIME_FOR_INSTALLER = 2000;
+
+	/**
+	 * constructor to create this handler, usually via Guice
+	 */
+	@Inject
+	public InstallJswordModuleHandler() {
+	}
+
+
+
+	public InstallJswordModuleResult execute(final InstallJswordModuleCommand cmd,
+		final ExecutionContext context) throws ActionException {
+
+		final String initials = cmd.getInitials();
+		if (initials == null) {
+			throw new ActionException("Module initials provided was null");
+		}
+
+		try {
+			final HttpSwordInstaller newCustomInstaller = getNewCustomInstaller();
+
+			// remove if already installed
+			final Book installed = Books.installed().getBook(initials);
+			if (installed != null) {
+				// remove first
+				// Books.installed().removeBook(installed);
+				installed.getDriver().delete(installed);
+				getLogger().debug(
+					String.format("%s (%s) is already installed, so removing first", initials,
+						installed.getName()));
+			}
+
+			// now kick off install
+			final Book bookToBeInstalled = newCustomInstaller.getBook(initials);
+			newCustomInstaller.install(bookToBeInstalled);
+
+			getLogger().debug(String.format("Installing %s", initials));
+
+			// finally wait for install to finish
+			// hack to wait for the thread to register with the manager
+			// TODO: check with jsword community
+			// TODO: use a timer instead...
+			Thread.sleep(WAIT_TIME_FOR_INSTALLER);
+
+			@SuppressWarnings("unchecked")
+			final Set<Progress> jswordJobs = JobManager.getJobs();
+			for (final Progress p : jswordJobs) {
+				if (p.getJobName().equals("Installing book: " + bookToBeInstalled.getName())) {
+					// TODO: expose join on the thread and wait for it to exit
+					// this will depend on the JSword community
+					while (!p.isFinished()) {
+						// sleep
+						Thread.sleep(WAIT_TIME_FOR_INSTALLER);
+					}
+				}
+			}
+		} catch (final BookException e) {
+			getLogger().error("An error occured during the installation of the book", e);
+		} catch (final InterruptedException e) {
+			getLogger().error("An error occurred during the downloading of the book", e);
+		}
+
+		// wait for module to be completed
+
+		return new InstallJswordModuleResult(true);
+	}
+
+	public void rollback(final InstallJswordModuleCommand arg0,
+		final InstallJswordModuleResult arg1, final ExecutionContext arg2) throws ActionException {
+		getLogger().error("Rolling back InstallJswordModule");
+	}
+
+	/**
+	 * TODO: needs redoing to ensure we take all the installers provided by
+	 * JSword
+	 * 
+	 * @return a custom installer configured with the crosswire proxy
+	 */
+	private HttpSwordInstaller getNewCustomInstaller() {
+		getLogger().info("Creating new installer for JSword");
+		final HttpSwordInstaller resourceInstaller = new HttpSwordInstaller();
+
+		getLogger().info("Currently hardcoded installer host to:" + "www.crosswire.org");
+		getLogger().info("Currently hardcoded property names for step");
+		final String host = "www.crosswire.org";
+		final String proxyHost = System.getProperty(PROXY_HOST);
+		final String proxyPort = System.getProperty(PROXY_PORT);
+		getLogger().info(
+			String.format("Setting to (%1$s via %2$s:%3$s)", "www.crosswire.org", proxyHost,
+				proxyPort));
+
+		resourceInstaller.setHost(host);
+		if (proxyHost != null) {
+			resourceInstaller.setProxyHost(proxyHost);
+		}
+		if (proxyPort != null) {
+			resourceInstaller.setProxyPort(Integer.parseInt(proxyPort));
+		}
+
+		getLogger().info("Setting package and catalog directories");
+		resourceInstaller.setPackageDirectory("/ftpmirror/pub/sword/packages/rawzip");
+		resourceInstaller.setCatalogDirectory("/ftpmirror/pub/sword/raw");
+		return resourceInstaller;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/StrongMorphMap.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/StrongMorphMap.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/handler/util/passage/StrongMorphMap.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,119 @@
+package com.tyndalehouse.step.web.server.handler.util.passage;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This map will store the mapping for strong,morph to the word However
+ * sometimes the morphology of the word is not present in the passage and since
+ * we still want to be able to render some sort of interlinear, it would be best
+ * to match just on the word as a result each entity will have the the three
+ * values associated to it text (what the word is) the strong number the
+ * morphology (optional) The map is keyed my strong number.
+ * 
+ * In order to ensure rapid lookup, we will use the following way of mapping
+ * elements Strong numbers will map either directly to the word when no morph is
+ * available, or through a morph to the word
+ * 
+ * TODO: It is assumed that given a strong and morph the text is unique TODO:
+ * change this, since there are multiple morphs per lemma and word strong
+ * ---------> morph --------> word (1) or strong ------------------------> word
+ * (2) A mapping (2) will not be stored if (1) is available, and therefore
+ * lookups lookup the morph first as this is prefered.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class StrongMorphMap {
+	// lemmas morphs word
+	/**
+	 * this map maps strong numbers to morphs. it is the first level of
+	 * indirection to the map of morphs which maps to a word
+	 */
+	private final Map<String, Map<String, String>> strongToMorph;
+
+	/**
+	 * this map maps the strong number ot the word directly
+	 */
+	private final Map<String, String> strongToWord;
+
+	/**
+	 * Default constructor that initialises the two maps
+	 */
+	public StrongMorphMap() {
+		strongToMorph = new HashMap<String, Map<String, String>>();
+		strongToWord = new HashMap<String, String>();
+	}
+
+	/**
+	 * only to be used if no morph is available
+	 * 
+	 * @param strong the strong number or lemma
+	 * @param word the word to be stored
+	 */
+	public final void addWord(final String strong, final String word) {
+		strongToWord.put(strong, word);
+	}
+
+	/**
+	 * adds a word to the map
+	 * 
+	 * @param strong the lemma/strong number
+	 * @param morph the morph / indicating morphology
+	 * @param word the word
+	 */
+	public final void addWord(final String strong, final String morph, final String word) {
+		if (morph == null) {
+			addWord(strong, word);
+			return;
+		}
+
+		Map<String, String> morphsToWords = strongToMorph.get(strong);
+		if (morphsToWords == null) {
+			morphsToWords = new HashMap<String, String>();
+			strongToMorph.put(strong, morphsToWords);
+		}
+
+		// guaranteed non-null map
+		morphsToWords.put(morph, word);
+	}
+
+	/**
+	 * Looks up the (lemma, morph) key in the map. If morph is null, lookup is
+	 * done solely on strong number, and takes the first of the morphs
+	 * 
+	 * @param lemma lemma associated to a a word
+	 * @param morph morph, can be passed in null, refering to the grammar of a
+	 *            word in a language
+	 * @return the word associated in the map to the (lemma, morph) combination
+	 */
+	// TODO: check for nulls on lemma
+	public final String get(final String lemma, final String morph) {
+		final Map<String, String> morphToWord = strongToMorph.get(lemma);
+
+		if (morphToWord != null) {
+			if (morph != null) {
+				// use the chain from morphs to word
+				final String word = morphToWord.get(morph);
+				if (word != null) {
+					return word;
+				} else {
+					// well we didn't find our morph, so the best option is to
+					// return another morph for the same strong number
+					final Collection<String> words = morphToWord.values();
+					final Iterator<String> wordsIterator = words.iterator();
+					if (wordsIterator.hasNext()) {
+						return wordsIterator.next();
+					}
+				}
+			}
+		}
+
+		// if we get here, there is nothing valuable in the map going through
+		// the morphs
+		// therefore, let's just return something from the other map
+		return strongToWord.get(lemma);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/ConfigurableHTMLConverter.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/ConfigurableHTMLConverter.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/ConfigurableHTMLConverter.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,170 @@
+/**
+ * Distribution License:
+ * BibleDesktop is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 2 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * The License is available on the internet at:
+ *       http://www.gnu.org/copyleft/gpl.html
+ * or by writing to:
+ *      Free Software Foundation, Inc.
+ *      59 Temple Place - Suite 330
+ *      Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2005
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: ConfigurableSwingConverter.java 1583 2007-07-30 17:04:04Z dmsmith $
+ */
+package com.tyndalehouse.step.web.server.jsword;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.MissingResourceException;
+
+import javax.xml.transform.TransformerException;
+
+import org.crosswire.common.util.FileUtil;
+import org.crosswire.common.util.NetUtil;
+import org.crosswire.common.util.ResourceUtil;
+import org.crosswire.common.util.URIFilter;
+import org.crosswire.common.xml.Converter;
+import org.crosswire.common.xml.SAXEventProvider;
+import org.crosswire.common.xml.TransformingSAXEventProvider;
+
+/**
+ * Turn XML from a Bible into HTML according to a Display style.
+ * 
+ * @see gnu.gpl.License for license details. The copyright to this program is
+ *      held by it's authors.
+ * @author Joe Walker [joe at eireneh dot com]
+ */
+public class ConfigurableHTMLConverter implements Converter {
+	/**
+     *
+     */
+	static final class XSLTFilter implements URIFilter {
+
+		public boolean accept(final String name) {
+			return name.endsWith(FileUtil.EXTENSION_XSLT);
+		}
+	}
+
+	/**
+	 * The font to be used in OSIS->HTML generation
+	 */
+	private static String font = "Serif-PLAIN-14"; //$NON-NLS-1$
+
+	/**
+	 * The stylesheet we are transforming using
+	 */
+	private static String style = "simple.xsl"; //$NON-NLS-1$
+
+	/**
+	 * ripped off JSWord: TODO: needs to be down properly
+	 */
+	public ConfigurableHTMLConverter() {
+
+	}
+
+	//
+	// /**
+	// * Accessor for the stylesheet we are transforming using
+	// */
+	// public static Font toFont()
+	// {
+	// return null;
+	// //return GuiConvert.string2Font(font);
+	// }
+
+	// /**
+	// * Accessor for the stylesheet we are transforming using
+	// */
+	// public static void setFont(String font)
+	// {
+	// ConfigurableHTMLConverter.font = font;
+	// XSLTProperty.FONT.setState(font);
+	// }
+
+	/**
+	 * Accessor for the stylesheet we are transforming using
+	 * 
+	 * @return the font
+	 */
+	public static String getFont() {
+		return font;
+	}
+
+	/**
+	 * Accessor for the stylesheet we are transforming using
+	 * 
+	 * @return the resource name
+	 */
+	public static String getResourceName() {
+		return style;
+	}
+
+	/**
+	 * Accessor for the stylesheet we are transforming using
+	 * 
+	 * @param style returns the resource name given a style
+	 */
+	public static void setResourceName(final String style) {
+		ConfigurableHTMLConverter.style = style;
+	}
+
+	/**
+	 * 
+	 * 
+	 * @see org.crosswire.common.xml.Converter#convert(org.crosswire.common.xml.
+	 *      SAXEventProvider)
+	 * @param xmlsep the sax event provider
+	 * @return the converted SAX event provider
+	 * @throws TransformerException thrown if something bad happens during the
+	 *             transformation of the xml
+	 */
+	public SAXEventProvider convert(final SAXEventProvider xmlsep) throws TransformerException {
+		try {
+			final String path = "xsl/cswing/" + style; //$NON-NLS-1$
+			final URL xslurl = ResourceUtil.getResource(path);
+
+			final TransformingSAXEventProvider tsep = new TransformingSAXEventProvider(NetUtil.toURI(xslurl),
+					xmlsep);
+			// We used to do:
+			// tsep.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+			// however for various reasons, now we don't but nothing seems to be
+			// broken ...
+			return tsep;
+		} catch (final MissingResourceException ex) {
+			throw new TransformerException(ex);
+		}
+	}
+
+	/**
+	 * Get an array of the available style names for a given subject. Different
+	 * subjects are available for different contexts. For example - for
+	 * insertion into a web page we might want to use a set that had complex
+	 * HTML, or IE/NS specific HTML, where as a JFC HTMLDocument needs simpler
+	 * HTML - and special tags like the starting &lt;HTML> tags.
+	 * <p>
+	 * If the protocol of the URL of the current directory is not file then we
+	 * can't use File.list to get the contents of the directory. This will
+	 * happen if this is being run as an applet. When we start doing that then
+	 * we will need to think up something smarter here. Until then we just
+	 * return a zero length array.
+	 * 
+	 * @return An array of available style names
+	 */
+	public String[] getStyles() {
+		try {
+			final String search = "xsl/cswing/" + NetUtil.INDEX_FILE; //$NON-NLS-1$
+			final URL index = ResourceUtil.getResource(search);
+			return NetUtil.listByIndexFile(NetUtil.toURI(index), new XSLTFilter());
+		} catch (final IOException ex) {
+			return new String[0];
+		}
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/XSLTProperty.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/XSLTProperty.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/server/jsword/XSLTProperty.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,321 @@
+/**
+ * Distribution License:
+ * BibleDesktop is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, version 2 as published by
+ * the Free Software Foundation. This program is distributed in the hope
+ * that it will be useful, but WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * The License is available on the internet at:
+ *       http://www.gnu.org/copyleft/gpl.html
+ * or by writing to:
+ *      Free Software Foundation, Inc.
+ *      59 Temple Place - Suite 330
+ *      Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2005
+ *     The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: XSLTProperty.java 1583 2007-07-30 17:04:04Z dmsmith $
+ */
+package com.tyndalehouse.step.web.server.jsword;
+
+import java.io.File;
+import java.io.Serializable;
+import java.net.MalformedURLException;
+
+import org.crosswire.common.util.NetUtil;
+import org.crosswire.common.util.Reporter;
+import org.crosswire.common.xml.TransformingSAXEventProvider;
+
+/* TODO: redo this class properly to behave as per where it cam from!
+ * 
+ */
+
+/**
+ * Defines properties that control the behavior of translating OSIS to HTML.
+ * 
+ * @see gnu.gpl.License for license details. The copyright to this program is
+ *      held by it's authors.
+ * @author DM Smith [ dmsmith555 at yahoo dot com]
+ */
+ at SuppressWarnings(value = {})
+public final class XSLTProperty implements Serializable {
+	/**
+	 * What is the base of the current document. Note this needs to be set each
+	 * time the document is shown.
+	 */
+	public static final XSLTProperty BASE_URL = new XSLTProperty("baseURL", "", true); //$NON-NLS-1$ //$NON-NLS-2$
+
+	/**
+	 * Show book, chapter and verse numbers.
+	 */
+	public static final XSLTProperty BCV = new XSLTProperty("BCVNum", false); //$NON-NLS-1$
+
+	/**
+	 * What is the base of the current document.
+	 */
+	public static final XSLTProperty CSS = new XSLTProperty("css", "", true); //$NON-NLS-1$ //$NON-NLS-2$
+
+	/**
+	 * Show chapter and verse numbers.
+	 */
+	public static final XSLTProperty CV = new XSLTProperty("CVNum", false); //$NON-NLS-1$
+
+	/**
+	 * What is the base of the current document. Note this needs to be set each
+	 * time the document is shown.
+	 */
+	public static final XSLTProperty DIRECTION = new XSLTProperty("direction", ""); //$NON-NLS-1$ //$NON-NLS-2$
+
+	/**
+	 * What is the base of the current document. Note this needs to be set each
+	 * time the font changes.
+	 */
+	public static final XSLTProperty FONT = new XSLTProperty("font", "Serif-PLAIN-14"); //$NON-NLS-1$ //$NON-NLS-2$
+
+	/**
+	 * Should headings be shown
+	 */
+	public static final XSLTProperty HEADINGS = new XSLTProperty("Headings", true); //$NON-NLS-1$
+
+	/**
+	 * Determines whether Word Morphology (e.g. Robinson) should show
+	 */
+	public static final XSLTProperty MORPH = new XSLTProperty("Morph", false); //$NON-NLS-1$
+
+	/**
+	 * Show no verse numbers
+	 */
+	public static final XSLTProperty NO_VERSE_NUMBERS = new XSLTProperty("NoVNum", false); //$NON-NLS-1$
+
+	/**
+	 * Should notes be shown
+	 */
+	public static final XSLTProperty NOTES = new XSLTProperty("Notes", true); //$NON-NLS-1$
+
+	/**
+	 * Determines whether verses should start on a new line.
+	 */
+	public static final XSLTProperty START_VERSE_ON_NEWLINE = new XSLTProperty("VLine", false); //$NON-NLS-1$
+
+	/**
+	 * Determines whether Strong's Numbers should show
+	 */
+	public static final XSLTProperty STRONGS_NUMBERS = new XSLTProperty("Strongs", false); //$NON-NLS-1$
+
+	/**
+	 * Show verse numbers as a superscript.
+	 */
+	public static final XSLTProperty TINY_VERSE_NUMBERS = new XSLTProperty("TinyVNum", true); //$NON-NLS-1$
+
+	/**
+	 * Show verse numbers
+	 */
+	public static final XSLTProperty VERSE_NUMBERS = new XSLTProperty("VNum", true); //$NON-NLS-1$
+
+	/**
+	 * Should cross references be shown
+	 */
+	public static final XSLTProperty XREF = new XSLTProperty("XRef", true); //$NON-NLS-1$
+
+	/**
+	 * Support for serialization
+	 * 
+	 */
+	private static int nextObj;
+
+	/**
+	 * Serialization ID
+	 */
+	private static final long serialVersionUID = 3257567325749326905L;
+
+	/**
+	 * list of xslt properties
+	 */
+	private static final XSLTProperty[] VALUES = { STRONGS_NUMBERS, MORPH, START_VERSE_ON_NEWLINE,
+			VERSE_NUMBERS, CV, BCV, NO_VERSE_NUMBERS, TINY_VERSE_NUMBERS, HEADINGS, NOTES, XREF, BASE_URL,
+			DIRECTION, FONT, CSS, };
+
+	/**
+	 * Whether the string state should be converted to an URL when setting the
+	 * property.
+	 */
+	private final boolean asURL;
+
+	/**
+	 * The default state of the XSLTProperty
+	 */
+	private final String defaultState;
+
+	/**
+	 * The name of the XSLTProperty
+	 */
+	private final String name;
+
+	/**
+	 * TODO: don't know what this does, this class is a copy from JSword which
+	 * needs revamping
+	 */
+	private final int obj = nextObj++;
+
+	/**
+	 * The current state of the XSLTProperty
+	 */
+	private String state;
+
+	/**
+	 * @param name The name of this property
+	 * @param defaultState The initial state of the property.
+	 */
+	private XSLTProperty(final String name, final boolean defaultState) {
+		this(name, Boolean.toString(defaultState));
+	}
+
+	/**
+	 * @param name The name of this property
+	 * @param defaultState The initial state of the property.
+	 */
+	private XSLTProperty(final String name, final String defaultState) {
+		this(name, defaultState, false);
+	}
+
+	/**
+	 * @param name The name of this property
+	 * @param defaultState The initial state of the property.
+	 * @param asURL whether it is a uRl?
+	 */
+	private XSLTProperty(final String name, final String defaultState, final boolean asURL) {
+		this.name = name;
+		this.defaultState = defaultState;
+		this.state = defaultState;
+		this.asURL = asURL;
+	}
+
+	/**
+	 * Lookup method to convert from an integer
+	 * 
+	 * @param i gets a particular xslt property
+	 * @return the XSLT property matching the index
+	 */
+	public static XSLTProperty fromInteger(final int i) {
+		return VALUES[i];
+	}
+
+	/**
+	 * Lookup method to convert from a String
+	 * 
+	 * @param name a linear search for a property and returns the XSLT property
+	 * @return a XSLT property
+	 */
+	public static XSLTProperty fromString(final String name) {
+		for (int i = 0; i < VALUES.length; i++) {
+			final XSLTProperty o = VALUES[i];
+			if (o.name.equalsIgnoreCase(name)) {
+				return o;
+			}
+		}
+		assert false;
+		return null;
+	}
+
+	/**
+	 * 
+	 * @param provider sets the SAX provider
+	 */
+	public static void setProperties(final TransformingSAXEventProvider provider) {
+		for (int i = 0; i < VALUES.length; i++) {
+			VALUES[i].setProperty(provider);
+		}
+	}
+
+	/**
+	 * 
+	 * @return default state
+	 */
+	public boolean getDefaultState() {
+		return Boolean.valueOf(defaultState).booleanValue();
+	}
+
+	/**
+	 * 
+	 * @return default state as a string
+	 */
+	public String getDefaultStringState() {
+		return defaultState;
+	}
+
+	/**
+	 * @return the name of the property
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @return the state
+	 */
+	public boolean getState() {
+		return Boolean.valueOf(state).booleanValue();
+	}
+
+	/**
+	 * 
+	 * @return state as a string
+	 */
+	public String getStringState() {
+		return state;
+	}
+
+	/**
+	 * 
+	 * @param provider a SAX provider
+	 */
+	public void setProperty(final TransformingSAXEventProvider provider) {
+		if (state != null && state.length() > 0) {
+			String theState = state;
+			if (asURL) {
+				try {
+					theState = NetUtil.getURI(new File(state)).toURL().toString();
+				} catch (final MalformedURLException ex) {
+					Reporter.informUser(this, ex);
+				}
+			}
+			provider.setParameter(name, theState);
+		}
+	}
+
+	/**
+	 * @param newState sets the state to newState
+	 */
+	public void setState(final boolean newState) {
+		state = Boolean.toString(newState);
+	}
+
+	/**
+	 * @param newState sets the state to newState
+	 */
+	public void setState(final String newState) {
+		state = newState;
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see java.lang.Object#toString()
+	 */
+	@Override
+	public String toString() {
+		return name;
+	}
+
+	/**
+	 * TODO: redo this whole class
+	 * 
+	 * @return an object
+	 */
+	Object readResolve() {
+		return VALUES[obj];
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/BooksRequiredType.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/BooksRequiredType.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/BooksRequiredType.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,14 @@
+package com.tyndalehouse.step.web.shared.command;
+
+/**
+ * Describing what kind of book to be displayed
+ * 
+ * @author CJBurrell
+ * 
+ */
+public enum BooksRequiredType {
+	/**
+	 * only retrieve bibles
+	 */
+	BIBLE,
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetAvailableBibleVersionsCommand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetAvailableBibleVersionsCommand.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetAvailableBibleVersionsCommand.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,46 @@
+package com.tyndalehouse.step.web.shared.command;
+
+import net.customware.gwt.dispatch.shared.Action;
+
+import com.tyndalehouse.step.web.shared.result.GetAvailableBibleVersionsResult;
+
+/**
+ * Commmand to get available set of books, that are installed on the server
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetAvailableBibleVersionsCommand implements Action<GetAvailableBibleVersionsResult> {
+	/**
+	 * serial id.
+	 */
+	private static final long serialVersionUID = 5781027650600417430L;
+
+	// TODO: later change that to list modules, bibles, etc.
+	/**
+	 * Describes which types of modules are required to be returned.
+	 */
+	private BooksRequiredType booksRequired = BooksRequiredType.BIBLE;
+
+	/**
+	 * Default constructor needs to be available for GWT it seems.
+	 */
+	public GetAvailableBibleVersionsCommand() {
+
+	}
+
+	/**
+	 * @return the booksRequired
+	 */
+	public BooksRequiredType getBooksRequired() {
+		return booksRequired;
+	}
+
+	/**
+	 * @param booksRequired the booksRequired to set
+	 */
+	public void setBooksRequired(final BooksRequiredType booksRequired) {
+		this.booksRequired = booksRequired;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetBibleBooksCommand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetBibleBooksCommand.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetBibleBooksCommand.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,40 @@
+package com.tyndalehouse.step.web.shared.command;
+
+import net.customware.gwt.dispatch.shared.Action;
+
+import com.tyndalehouse.step.web.shared.result.GetBibleBooksCommandResult;
+
+/**
+ * This is currently based on the KJV and ensures that all bible books are
+ * returned to the UI.
+ * 
+ * @author CJBurrell
+ * 
+ */
+
+public class GetBibleBooksCommand implements Action<GetBibleBooksCommandResult> {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 2749008090105331922L;
+
+	/**
+	 * Initials of version to use to lookup bible
+	 */
+	private String initials;
+
+	/**
+	 * @return the initials
+	 */
+	public final String getInitials() {
+		return initials;
+	}
+
+	/**
+	 * @param initials the initials to set
+	 */
+	public final void setInitials(final String initials) {
+		this.initials = initials;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetCurrentBibleTextCommand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetCurrentBibleTextCommand.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetCurrentBibleTextCommand.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,107 @@
+package com.tyndalehouse.step.web.shared.command;
+
+import net.customware.gwt.dispatch.shared.Action;
+
+import com.tyndalehouse.step.web.shared.common.scripturelookup.BibleTextLookupType;
+import com.tyndalehouse.step.web.shared.result.GetCurrentBibleTextResult;
+
+/**
+ * Contains the details of a request for biblical text. Such details include
+ * whether to use a plain text, a standard XSLT, or a logical form
+ * <p>
+ * For logical form (represented in Bean form) we allow the use of interlinears
+ * as well.
+ * <p>
+ * A classic interlinear is where the original text is the master copy of the
+ * text, and the translated (English, French, etc.) text is lined up underneath
+ * <p>
+ * A reverse interlinear is where the the English/French text is on top, and the
+ * original (Hebrew or Greek) is lined up underneath.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class GetCurrentBibleTextCommand implements Action<GetCurrentBibleTextResult> {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -6828956918275592036L;
+
+	/**
+	 * the biblical reference, for e.g. Gen 1:1
+	 */
+	private String reference;
+
+	/**
+	 * type of lookup to make
+	 */
+	private BibleTextLookupType typeOfLookup;
+
+	// TODO: add validation to the handler/client to ensure that
+	// version/interlinear matches correctly
+	/**
+	 * the version of the bible to use.
+	 */
+	private String version;
+
+	/**
+	 * default constructor TODO: can this be made private? I think so
+	 */
+	public GetCurrentBibleTextCommand() {
+
+	}
+
+	/**
+	 * constructor for a version,reference combo
+	 * 
+	 * @param version version to be used in the lookup (intials)
+	 * @param reference reference to be used in the lookup (for e.g. Gen 1:1)
+	 */
+	public GetCurrentBibleTextCommand(final String version, final String reference) {
+		this.version = version;
+		this.reference = reference;
+	}
+
+	/**
+	 * @return the biblical reference (Gen 1:1-5 for example)
+	 */
+	public String getReference() {
+		return reference;
+	}
+
+	/**
+	 * @return the typeOfLookup
+	 */
+	public final BibleTextLookupType getTypeOfLookup() {
+		return typeOfLookup;
+	}
+
+	/**
+	 * @return the initials of the version to be used in the lookup
+	 */
+	public String getVersion() {
+		return version;
+	}
+
+	/**
+	 * @param reference the reference to set
+	 */
+	public void setReference(final String reference) {
+		this.reference = reference;
+	}
+
+	/**
+	 * @param typeOfLookup the typeOfLookup to set
+	 */
+	public final void setTypeOfLookup(final BibleTextLookupType typeOfLookup) {
+		this.typeOfLookup = typeOfLookup;
+	}
+
+	/**
+	 * @param version the version to set
+	 */
+	public void setVersion(final String version) {
+		this.version = version;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetDictionaryDefinitionCommand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetDictionaryDefinitionCommand.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetDictionaryDefinitionCommand.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,46 @@
+package com.tyndalehouse.step.web.shared.command;
+
+import java.util.List;
+
+import net.customware.gwt.dispatch.shared.Action;
+
+import com.tyndalehouse.step.web.shared.result.GetDictionaryDefinitionResult;
+
+/**
+ * dictionary definition command, contains the references to lookup
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetDictionaryDefinitionCommand implements Action<GetDictionaryDefinitionResult> {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -6139208624046856543L;
+
+	/**
+	 * references to be looked up
+	 */
+	private List<String> lookupReferencce;
+
+	/**
+	 * the public constructor
+	 */
+	public GetDictionaryDefinitionCommand() {
+
+	}
+
+	/**
+	 * @return the lookupReferencce
+	 */
+	public List<String> getLookupReferencce() {
+		return lookupReferencce;
+	}
+
+	/**
+	 * @param lookupReferences the list lookupReferencce to set
+	 */
+	public void setLookupReference(final List<String> lookupReferences) {
+		this.lookupReferencce = lookupReferences;
+	}
+}

Added: 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	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetEventsForDateRangeCommand.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,78 @@
+package com.tyndalehouse.step.web.shared.command;
+
+import java.util.List;
+
+import net.customware.gwt.dispatch.shared.Action;
+
+import com.tyndalehouse.step.web.shared.common.timeline.TimeBandVisibleDate;
+import com.tyndalehouse.step.web.shared.result.GetEventsForDateRangeResult;
+
+/**
+ * Contains the details of a request for events within a particular date range.
+ * This contains a list of @see {@link TimeBandVisibleDate}, which records the
+ * portion of time to be requested from the server
+ * 
+ * @author cjburrell
+ * 
+ */
+public class GetEventsForDateRangeCommand implements Action<GetEventsForDateRangeResult> {
+	/**
+	 * default uid
+	 */
+	private static final long serialVersionUID = 5781027650600417430L;
+
+	/**
+	 * 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;
+
+	/**
+	 * Used for serialization
+	 */
+	public GetEventsForDateRangeCommand() {
+
+	}
+
+	/**
+	 * default constructor that should be used
+	 * 
+	 * @param visbleDates list of date ranges encapsulated in a
+	 *            TimeBandVisibleDate object
+	 */
+	public GetEventsForDateRangeCommand(final List<TimeBandVisibleDate> visbleDates) {
+		this.visbleDates = visbleDates;
+	}
+
+	/**
+	 * @return the visbleDates
+	 */
+	public List<TimeBandVisibleDate> getVisbleDates() {
+		return visbleDates;
+	}
+
+	/**
+	 * @return the showDuration
+	 */
+	public boolean isShowDuration() {
+		return showDuration;
+	}
+
+	/**
+	 * @param showDuration the showDuration to set
+	 */
+	public void setShowDuration(final boolean showDuration) {
+		this.showDuration = showDuration;
+	}
+
+	/**
+	 * @param visbleDates the visbleDates to set
+	 */
+	public void setVisbleDates(final List<TimeBandVisibleDate> visbleDates) {
+		this.visbleDates = visbleDates;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetLocationsCommand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetLocationsCommand.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetLocationsCommand.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,21 @@
+package com.tyndalehouse.step.web.shared.command;
+
+import net.customware.gwt.dispatch.shared.Action;
+
+import com.tyndalehouse.step.web.shared.result.GetLocationsResult;
+
+/**
+ * This command captures the input to the handler to query the server for all
+ * locations pertaining to a particular passage
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetLocationsCommand implements Action<GetLocationsResult> {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -4636855791737543490L;
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetTimelineOriginForScriptureCommand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetTimelineOriginForScriptureCommand.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetTimelineOriginForScriptureCommand.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,54 @@
+package com.tyndalehouse.step.web.shared.command;
+
+import net.customware.gwt.dispatch.shared.Action;
+
+import com.tyndalehouse.step.web.shared.result.GetTimelineOriginForScriptureResult;
+
+/**
+ * The command to retrieve the best event given a verse range
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetTimelineOriginForScriptureCommand implements Action<GetTimelineOriginForScriptureResult> {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -6454957611866927920L;
+	/**
+	 * default uid
+	 */
+
+	private String scriptureReference;
+
+	/**
+	 * default constructor that should be used
+	 * 
+	 * @param scriptureReference the biblical reference/range to be looked up
+	 */
+	public GetTimelineOriginForScriptureCommand(final String scriptureReference) {
+		this.scriptureReference = scriptureReference;
+	}
+
+	/**
+	 * Used for serialization
+	 */
+	@SuppressWarnings("unused")
+	private GetTimelineOriginForScriptureCommand() {
+
+	}
+
+	/**
+	 * @return the scriptureReference
+	 */
+	public String getScriptureReference() {
+		return scriptureReference;
+	}
+
+	/**
+	 * @param scriptureReference the scriptureReference to set
+	 */
+	public void setScriptureReference(final String scriptureReference) {
+		this.scriptureReference = scriptureReference;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetTimelineUISetupCommand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetTimelineUISetupCommand.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/GetTimelineUISetupCommand.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,27 @@
+package com.tyndalehouse.step.web.shared.command;
+
+import net.customware.gwt.dispatch.shared.Action;
+
+import com.tyndalehouse.step.web.shared.result.GetTimelineUISetupResult;
+
+/**
+ * command to request all the initial information useful to set up a timeline
+ * component, including the list of timebands, their recommended units, etc.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetTimelineUISetupCommand implements Action<GetTimelineUISetupResult> {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 7813083800240239846L;
+
+	/**
+	 * public constructor
+	 */
+	public GetTimelineUISetupCommand() {
+
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/InstallJswordModuleCommand.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/InstallJswordModuleCommand.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/command/InstallJswordModuleCommand.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,45 @@
+package com.tyndalehouse.step.web.shared.command;
+
+import net.customware.gwt.dispatch.shared.Action;
+
+import com.tyndalehouse.step.web.shared.result.InstallJswordModuleResult;
+
+/**
+ * Requests the server (or local server) to install a bible version
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class InstallJswordModuleCommand implements Action<InstallJswordModuleResult> {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 3416377875572322721L;
+
+	/**
+	 * the initials to be used to check/install the book
+	 */
+	private String initials;
+
+	/**
+	 * the install jsword module command constructor
+	 */
+	public InstallJswordModuleCommand() {
+
+	}
+
+	/**
+	 * @return the initials of module to be installed
+	 */
+	public String getInitials() {
+		return initials;
+	}
+
+	/**
+	 * @param initials the initials of the module to set
+	 */
+	public void setInitials(final String initials) {
+		this.initials = initials;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/GeoLocation.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/GeoLocation.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/GeoLocation.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,140 @@
+package com.tyndalehouse.step.web.shared.common.maps;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Serialisable POJO containing all the data pertaining to displaying the
+ * location on the screen
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GeoLocation implements Serializable {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -2429722523530262993L;
+
+	/**
+	 * description of the location
+	 */
+	private String description;
+
+	/**
+	 * value of the latitude
+	 */
+	private long latitude;
+
+	/**
+	 * List of lat longs
+	 */
+	private List<LatLong> latlongs;
+
+	/**
+	 * type of location, for e.g. a city, a memorial, a fountain, etc.
+	 */
+	private GeoLocationType locationType;
+
+	/**
+	 * value of the longitude
+	 */
+	private long longitude;
+
+	/**
+	 * Name of the place, for e.g. Golgotha
+	 */
+	private String placeName;
+
+	/**
+	 * default constructor
+	 */
+	public GeoLocation() {
+		latlongs = new ArrayList<LatLong>();
+	}
+
+	/**
+	 * @return the description
+	 */
+	public final String getDescription() {
+		return description;
+	}
+
+	/**
+	 * @return the latitude
+	 */
+	public final long getLatitude() {
+		return latitude;
+	}
+
+	/**
+	 * @return the latlongs
+	 */
+	public final List<LatLong> getLatlongs() {
+		return latlongs;
+	}
+
+	/**
+	 * @return the locationType
+	 */
+	public final GeoLocationType getLocationType() {
+		return locationType;
+	}
+
+	/**
+	 * @return the longitude
+	 */
+	public final long getLongitude() {
+		return longitude;
+	}
+
+	/**
+	 * @return the placeName
+	 */
+	public final String getPlaceName() {
+		return placeName;
+	}
+
+	/**
+	 * @param description the description to set
+	 */
+	public final void setDescription(final String description) {
+		this.description = description;
+	}
+
+	/**
+	 * @param latitude the latitude to set
+	 */
+	public final void setLatitude(final long latitude) {
+		this.latitude = latitude;
+	}
+
+	/**
+	 * @param latlongs the latlongs to set
+	 */
+	public final void setLatlongs(final List<LatLong> latlongs) {
+		this.latlongs = latlongs;
+	}
+
+	/**
+	 * @param locationType the locationType to set
+	 */
+	public final void setLocationType(final GeoLocationType locationType) {
+		this.locationType = locationType;
+	}
+
+	/**
+	 * @param longitude the longitude to set
+	 */
+	public final void setLongitude(final long longitude) {
+		this.longitude = longitude;
+	}
+
+	/**
+	 * @param placeName the placeName to set
+	 */
+	public final void setPlaceName(final String placeName) {
+		this.placeName = placeName;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/GeoLocationType.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/GeoLocationType.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/GeoLocationType.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,18 @@
+package com.tyndalehouse.step.web.shared.common.maps;
+
+/**
+ * Type of location, indicating whether the location is a city, a wall, a
+ * region, etc.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public enum GeoLocationType {
+	/** CITY */
+	CITY,
+	/** A FOUNTAIN */
+	FOUNTAIN,
+	/** A REGION */
+	REGION,
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/LatLong.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/LatLong.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/maps/LatLong.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,47 @@
+package com.tyndalehouse.step.web.shared.common.maps;
+
+/**
+ * LatLong POJO containg the latitude and longitude of a point on a map
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class LatLong {
+	/**
+	 * latitude of the point
+	 */
+	private long latitude;
+
+	/**
+	 * longitude of the point
+	 */
+	private long longitude;
+
+	/**
+	 * @return the latitude
+	 */
+	public final long getLatitude() {
+		return latitude;
+	}
+
+	/**
+	 * @return the longitude
+	 */
+	public final long getLongitude() {
+		return longitude;
+	}
+
+	/**
+	 * @param latitude the latitude to set
+	 */
+	public final void setLatitude(final long latitude) {
+		this.latitude = latitude;
+	}
+
+	/**
+	 * @param longitude the longitude to set
+	 */
+	public final void setLongitude(final long longitude) {
+		this.longitude = longitude;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/scripturelookup/BibleTextLookupType.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/scripturelookup/BibleTextLookupType.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/scripturelookup/BibleTextLookupType.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,20 @@
+package com.tyndalehouse.step.web.shared.common.scripturelookup;
+
+/**
+ * This enum indicates what kind of lookup is required from the server
+ * 
+ * @author CJBurrell
+ * 
+ */
+public enum BibleTextLookupType {
+	/** a classic interlinear is required */
+	CLASSIC_INTERLINEAR,
+	/** a logical form, POJO form of the text is required */
+	LOGICAL,
+	/** only the text is required */
+	PLAIN_TEXT,
+	/** a reverse interlinear is required */
+	REVERSE_INTERLINEAR,
+	/** the text, using a default xslt is required */
+	XSLT,
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimeBandVisibleDate.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimeBandVisibleDate.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimeBandVisibleDate.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,136 @@
+package com.tyndalehouse.step.web.shared.common.timeline;
+
+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.
+ * 
+ * TODO: harmonize capital letters to be TimebandVisibleDate
+ * 
+ * @author cjburrell
+ * 
+ */
+public class TimeBandVisibleDate implements Serializable {
+
+	/**
+	 * default serial id
+	 */
+	private static final long serialVersionUID = -7384255321830177509L;
+
+	/**
+	 * max date visible on the timeband
+	 */
+	private long maxDate;
+
+	/**
+	 * min date visible on the time band
+	 */
+	private long minDate;
+
+	/**
+	 * true indicates no request is required on the server
+	 */
+	private boolean noRequest;
+
+	/**
+	 * time band id
+	 */
+	private int timebandId;
+
+	/**
+	 * so that
+	 * 
+	 * @param timebandId the timebandId referred to in the module
+	 * @param minDate minDate in the range of dates to ask the server
+	 * @param maxDate maxDate in the range of dates to the ask the server
+	 */
+	public TimeBandVisibleDate(final int timebandId, final long minDate, final long maxDate) {
+		this.timebandId = timebandId;
+		this.minDate = minDate;
+		this.maxDate = maxDate;
+		noRequest = false;
+	}
+
+	/**
+	 * removing default constructor from view of other callers. Only accessible
+	 * through reflection, and therefore GWT
+	 */
+	private TimeBandVisibleDate() {
+	}
+
+	/**
+	 * returns a TimeBandVisibleDate object tagged to indicate no request is
+	 * required on the server
+	 * 
+	 * @return a marked TimeBandVisibleDate object, marked with a flag saying no
+	 *         request is required
+	 */
+	public static TimeBandVisibleDate getNoRequest() {
+		final TimeBandVisibleDate tvd = new TimeBandVisibleDate();
+		tvd.setNoRequest(true);
+		return tvd;
+	}
+
+	/**
+	 * @return the maxDate
+	 */
+	public long getMaxDate() {
+		return maxDate;
+	}
+
+	/**
+	 * @return the minDate
+	 */
+	public long getMinDate() {
+		return minDate;
+	}
+
+	/**
+	 * @return the timebandId
+	 */
+	public int getTimebandId() {
+		return timebandId;
+	}
+
+	/**
+	 * 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 maxDate the maxDate to set
+	 */
+	public void setMaxDate(final long maxDate) {
+		this.maxDate = maxDate;
+	}
+
+	/**
+	 * @param minDate the minDate to set
+	 */
+	public void setMinDate(final long minDate) {
+		this.minDate = minDate;
+	}
+
+	/**
+	 * @param noRequest the noRequest to set
+	 */
+	public void setNoRequest(final boolean noRequest) {
+		this.noRequest = noRequest;
+	}
+
+	/**
+	 * @param timebandId the timebandId to set
+	 */
+	public void setTimebandId(final int timebandId) {
+		this.timebandId = timebandId;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimelineBean.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimelineBean.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimelineBean.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,130 @@
+package com.tyndalehouse.step.web.shared.common.timeline;
+
+import java.io.Serializable;
+
+/**
+ * Timeline bean represents the different timelines on which events can be
+ * found... TODO: should this be renamed timeband?
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class TimelineBean implements Serializable {
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -1734142151232501392L;
+
+	/**
+	 * Timeline description from the server layer
+	 */
+	private String timelineDescription;
+
+	/**
+	 * timeline id sent across the wire
+	 */
+	private int timelineId;
+
+	/**
+	 * unit to be used when first display the timeband
+	 */
+	private String unit;
+
+	/**
+	 * default constructor made public
+	 */
+	public TimelineBean() {
+
+	}
+
+	/**
+	 * @return the timelineDescription
+	 */
+	public String getTimelineDescription() {
+		return timelineDescription;
+	}
+
+	/**
+	 * @return the timelineId
+	 */
+	public int getTimelineId() {
+		return timelineId;
+	}
+
+	/**
+	 * @return the unit
+	 */
+	public String getUnit() {
+		return unit;
+	}
+
+	/**
+	 * @param timelineDescription the timelineDescription to set
+	 */
+	public void setTimelineDescription(final String timelineDescription) {
+		this.timelineDescription = timelineDescription;
+	}
+
+	/**
+	 * @param timelineId the timelineId to set
+	 */
+	public void setTimelineId(final int timelineId) {
+		this.timelineId = timelineId;
+	}
+
+	/**
+	 * sets the unit field
+	 * 
+	 * @param unit the unit to be set
+	 */
+	public void setUnit(final String unit) {
+		this.unit = unit;
+
+	}
+
+	// /**
+	// * @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;
+	// }
+
+	// /**
+	// * @return the timelineCode
+	// */
+	// public String getTimelineCode() {
+	// return timelineCode;
+	// }
+	//
+	// public void setEventCount(int eventCount) {
+	// this.eventCount = eventCount;
+	// }
+	//
+	// /**
+	// * @return the eventCount
+	// */
+	// public int getEventCount() {
+	// return eventCount;
+	// }
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimelineEventBean.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimelineEventBean.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/common/timeline/TimelineEventBean.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,235 @@
+package com.tyndalehouse.step.web.shared.common.timeline;
+
+import java.io.Serializable;
+
+/**
+ * An Time Event bean, containing all the relevant fields passed from the server
+ * to the client. For e.g. the description of the event, its id, the dates, etc.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class TimelineEventBean implements Serializable {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -7664806988001700477L;
+
+	/**
+	 * The certainty of dating, as provided in input CSV files
+	 */
+	private String certainty;
+
+	/**
+	 * the event id
+	 */
+	private int eventId;
+
+	/**
+	 * the type of the event, where we distinguish battles, from births, etc.
+	 * (TODO: still to be done)
+	 */
+	private int eventTypeId;
+
+	/**
+	 * the from date
+	 */
+	private Long fromDate;
+
+	/**
+	 * how precise the date is, whether to the day, month, etc. see schema
+	 * definition for details
+	 */
+	private String fromPrecision;
+
+	/**
+	 * Name/Description of the event
+	 */
+	private String name;
+
+	/**
+	 * The timeband/timeline on which the event should be displayed
+	 */
+	private int timelineId;
+
+	/**
+	 * the to-date in the case of a duration
+	 */
+	private Long toDate;
+
+	/**
+	 * the precision of the "to-date", whether to the day, month, etc. see
+	 * schema definition for details
+	 */
+	private String toPrecision;
+
+	/**
+	 * making public
+	 */
+	public TimelineEventBean() {
+
+	}
+
+	/**
+	 * a constructor to set up everything in one go
+	 * 
+	 * @param eventId the event id from the database
+	 * @param fromDate the from date, at which the event starts/is
+	 * @param toDate the to date, if the date is a duratio
+	 * @param fromPrecision how precise the from date is (see schema for more
+	 *            details)
+	 * @param toPrecision how precise the to date is (see schema for more
+	 *            details)
+	 * @param name the description of the event
+	 * @param timelineId the timeband on which to be located
+	 * @param importanceId the importance id as defined in the input files
+	 * @param certainty the certainty as defined in the input files
+	 * @param eventTypeId the event type, describing different types, and
+	 *            therefore different representations of the event on the UI
+	 * 
+	 */
+	// CHECKSTYLE:OFF
+	public TimelineEventBean(final int eventId, final Long fromDate, final Long toDate,
+			final String fromPrecision, final String toPrecision, final String name, final int timelineId,
+			final int importanceId, final String certainty, final int eventTypeId) {
+		// CHECKSTYLE:ON
+		this.eventId = eventId;
+		this.fromDate = fromDate;
+		this.toDate = toDate;
+		this.fromPrecision = fromPrecision;
+		this.toPrecision = toPrecision;
+		this.timelineId = timelineId;
+		this.certainty = certainty;
+		this.eventTypeId = eventTypeId;
+		this.name = name;
+	}
+
+	/**
+	 * @return the certainty
+	 */
+	public String getCertainty() {
+		return certainty;
+	}
+
+	/**
+	 * @return the eventId
+	 */
+	public int getEventId() {
+		return eventId;
+	}
+
+	/**
+	 * @return the eventTypeId
+	 */
+	public int getEventTypeId() {
+		return eventTypeId;
+	}
+
+	/**
+	 * @return the fromDate
+	 */
+	public Long getFromDate() {
+		return fromDate;
+	}
+
+	/**
+	 * @return the fromPrecision
+	 */
+	public String getFromPrecision() {
+		return fromPrecision;
+	}
+
+	/**
+	 * returns the name/description of the event
+	 * 
+	 * @return the description of the event
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @return the timelineId
+	 */
+	public int getTimelineId() {
+		return timelineId;
+	}
+
+	/**
+	 * @return the toDate
+	 */
+	public Long getToDate() {
+		return toDate;
+	}
+
+	/**
+	 * @return the toPrecision
+	 */
+	public String getToPrecision() {
+		return toPrecision;
+	}
+
+	/**
+	 * @param certainty the certainty to set
+	 */
+	public void setCertainty(final String certainty) {
+		this.certainty = certainty;
+	}
+
+	/**
+	 * @param eventId the eventId to set
+	 */
+	public void setEventId(final int eventId) {
+		this.eventId = eventId;
+	}
+
+	/**
+	 * @param eventTypeId the eventTypeId to set
+	 */
+	public void setEventTypeId(final int eventTypeId) {
+		this.eventTypeId = eventTypeId;
+	}
+
+	/**
+	 * @param fromDate the fromDate to set
+	 */
+	public void setFromDate(final Long fromDate) {
+		this.fromDate = fromDate;
+	}
+
+	/**
+	 * @param fromPrecision the fromPrecision to set
+	 */
+	public void setFromPrecision(final String fromPrecision) {
+		this.fromPrecision = fromPrecision;
+	}
+
+	/**
+	 * @param name the name to set
+	 */
+	public void setName(final String name) {
+		this.name = name;
+	}
+
+	/**
+	 * @param timelineId the timelineId to set
+	 */
+	public void setTimelineId(final int timelineId) {
+		this.timelineId = timelineId;
+	}
+
+	/**
+	 * @param toDate the toDate to set
+	 */
+	public void setToDate(final Long toDate) {
+		this.toDate = toDate;
+	}
+
+	/**
+	 * @param toPrecision the toPrecision to set
+	 */
+	public void setToPrecision(final String toPrecision) {
+		this.toPrecision = toPrecision;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetAvailableBibleVersionsResult.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetAvailableBibleVersionsResult.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetAvailableBibleVersionsResult.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,54 @@
+package com.tyndalehouse.step.web.shared.result;
+
+import java.util.Collections;
+import java.util.SortedMap;
+
+import net.customware.gwt.dispatch.shared.Result;
+
+/**
+ * This is in response to a @see
+ * {@link com.tyndalehouse.step.web.share.command.GetAvailableBibleVersionsCommand}
+ * In essence, this contains a sorted map of books to be displayed on the UI.
+ * The intials are the key into JSword and should be used at all times when sent
+ * back to the server.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class GetAvailableBibleVersionsResult implements Result {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 1441380470741483969L;
+
+	/**
+	 * a map keyed from the initials (link into JSword) to the name of the book
+	 */
+	private SortedMap<String, String> books;
+
+	/**
+	 * constructor passing in the map of available bible versions
+	 * 
+	 * @param map map containing combinations of (key, book name)
+	 */
+	public GetAvailableBibleVersionsResult(final SortedMap<String, String> map) {
+		this.books = map;
+	}
+
+	/**
+	 * used for reflection
+	 */
+	@SuppressWarnings("unused")
+	private GetAvailableBibleVersionsResult() {
+
+	}
+
+	/**
+	 * the map of available books
+	 * 
+	 * @return the map of available books
+	 */
+	public SortedMap<String, String> getBooks() {
+		return Collections.unmodifiableSortedMap(books);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetBibleBooksCommandResult.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetBibleBooksCommandResult.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetBibleBooksCommandResult.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,52 @@
+package com.tyndalehouse.step.web.shared.result;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import net.customware.gwt.dispatch.shared.Result;
+
+/**
+ * Result from the GetBibleBooksCommand which contains the list of books
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetBibleBooksCommandResult implements Result {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -26170538247007172L;
+
+	/**
+	 * the list of books
+	 */
+	private List<String> books;
+
+	/**
+	 * the list of bible books provided to the constructor
+	 * 
+	 * @param books the list of books
+	 */
+	public GetBibleBooksCommandResult(final List<String> books) {
+		this.books = books;
+	}
+
+	/**
+	 * this constructor is used for reflection and must be present
+	 */
+	@SuppressWarnings("unused")
+	private GetBibleBooksCommandResult() {
+
+	}
+
+	/**
+	 * returns a list of books
+	 * 
+	 * @return the list of books
+	 */
+	public Collection<String> getBooks() {
+		return Collections.unmodifiableList(books);
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetCurrentBibleTextResult.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetCurrentBibleTextResult.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetCurrentBibleTextResult.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,83 @@
+package com.tyndalehouse.step.web.shared.result;
+
+import net.customware.gwt.dispatch.shared.Result;
+
+import com.tyndalehouse.step.web.shared.scripture.Passage;
+
+/**
+ * Result from a command, representing a biblical text
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetCurrentBibleTextResult implements Result {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -5781394877510591218L;
+
+	/**
+	 * the passage in logical form
+	 */
+	private Passage passage;
+
+	/**
+	 * the passage text
+	 */
+	private String passageText;
+
+	/**
+	 * The xslted text
+	 */
+	private String xsltedText;
+
+	/**
+	 * returns the logical form passage
+	 * 
+	 * @return the logical form of the passage
+	 */
+	public Passage getPassage() {
+		return passage;
+	}
+
+	/**
+	 * returns the passage text
+	 * 
+	 * @return the passage text
+	 */
+	public String getPassageText() {
+		return passageText;
+	}
+
+	/**
+	 * @return the xsltedText
+	 */
+	public String getXsltedText() {
+		return xsltedText;
+	}
+
+	/**
+	 * sets the logical form of the passage
+	 * 
+	 * @param p passage
+	 */
+	public void setPassage(final Passage p) {
+		this.passage = p;
+	}
+
+	/**
+	 * @param passageText the passageText to set
+	 */
+	public void setPassageText(final String passageText) {
+		this.passageText = passageText;
+	}
+
+	/**
+	 * @param xsltedText the xsltedText to set
+	 */
+	public void setXsltedText(final String xsltedText) {
+		this.xsltedText = xsltedText;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetDictionaryDefinitionResult.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetDictionaryDefinitionResult.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetDictionaryDefinitionResult.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,53 @@
+package com.tyndalehouse.step.web.shared.result;
+
+import net.customware.gwt.dispatch.shared.Result;
+
+/**
+ * The dictionary definition that was looked up from the
+ * GetDictionaryDefinitionCommand
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetDictionaryDefinitionResult implements Result {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 3121326970467885008L;
+
+	/**
+	 * the xslted definition of the definition that was looked up
+	 */
+	private String xsltedDefinition;
+
+	/**
+	 * Default constructor
+	 */
+	public GetDictionaryDefinitionResult() {
+
+	}
+
+	/**
+	 * @return the xsltedDefinition
+	 */
+	public String getXsltedDefinition() {
+		return xsltedDefinition;
+	}
+
+	/**
+	 * sets the definition
+	 * 
+	 * @param xsltedDefinition the definition to be set
+	 */
+	public void setDefinition(final String xsltedDefinition) {
+		this.xsltedDefinition = xsltedDefinition;
+	}
+
+	/**
+	 * @param xsltedDefinition the xsltedDefinition to set
+	 */
+	public void setXsltedDefinition(final String xsltedDefinition) {
+		this.xsltedDefinition = xsltedDefinition;
+	}
+}

Added: 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	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetEventsForDateRangeResult.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,56 @@
+package com.tyndalehouse.step.web.shared.result;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.customware.gwt.dispatch.shared.Result;
+
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineEventBean;
+
+/**
+ * Result containing all events requested within a particular date range.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetEventsForDateRangeResult implements Result {
+
+	/**
+	 * default serial id
+	 */
+	private static final long serialVersionUID = 7118668612721569823L;
+
+	/** list of events */
+	private List<TimelineEventBean> events = new ArrayList<TimelineEventBean>();
+
+	/**
+	 * public constructor
+	 */
+	public GetEventsForDateRangeResult() {
+
+	}
+
+	/**
+	 * Adds a new Event in Tim to the response
+	 * 
+	 * @param teb the event to add to the response
+	 */
+	public void add(final TimelineEventBean teb) {
+		getEvents().add(teb);
+
+	}
+
+	/**
+	 * @return a list of events within a specified date range
+	 */
+	public List<TimelineEventBean> getEvents() {
+		return events;
+	}
+
+	/**
+	 * @param events the events to set
+	 */
+	public void setEvents(final List<TimelineEventBean> events) {
+		this.events = events;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetLocationsResult.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetLocationsResult.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetLocationsResult.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,50 @@
+package com.tyndalehouse.step.web.shared.result;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import net.customware.gwt.dispatch.shared.Result;
+
+import com.tyndalehouse.step.web.shared.common.maps.GeoLocation;
+
+/**
+ * This object contains the result from a geographical location, containing
+ * enough data to display a marker on the screen, and a hover over.
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetLocationsResult implements Result {
+
+	/**
+	 * serial id for serialisation
+	 */
+	private static final long serialVersionUID = 1516648078862839012L;
+
+	/**
+	 * list of locations
+	 */
+	private List<GeoLocation> locations;
+
+	/**
+	 * default constructor
+	 */
+	public GetLocationsResult() {
+		locations = new ArrayList<GeoLocation>();
+	}
+
+	/**
+	 * @return the locations
+	 */
+	public final List<GeoLocation> getLocations() {
+		return locations;
+	}
+
+	/**
+	 * @param locations the locations to set
+	 */
+	public final void setLocations(final List<GeoLocation> locations) {
+		this.locations = locations;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetTimelineOriginForScriptureResult.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetTimelineOriginForScriptureResult.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetTimelineOriginForScriptureResult.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,131 @@
+package com.tyndalehouse.step.web.shared.result;
+
+import net.customware.gwt.dispatch.shared.Result;
+
+import com.tyndalehouse.step.web.shared.timeline.Unit;
+
+/**
+ * Result from querying the server for the best event to use as the origin of
+ * the timeline. This event is the one that best suits the verse range provided
+ * by the user
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class GetTimelineOriginForScriptureResult implements Result {
+	/**
+	 * generated serial version id
+	 */
+	private static final long serialVersionUID = 4256230588330550554L;
+
+	/**
+	 * whether no data was returned, because no events matched the biblical
+	 * reference
+	 */
+	private boolean isEmpty;
+
+	/**
+	 * the date of the recommended
+	 */
+	private Long originDate;
+
+	/**
+	 * the suggested timescale the UI should use
+	 */
+	private Unit suggestedTimeScale;
+
+	/**
+	 * the timeband id on which this date should be used
+	 */
+	private int timebandId;
+
+	/**
+	 * public constructor for this result object
+	 * 
+	 * @param isEmpty true if no data was found
+	 */
+	public GetTimelineOriginForScriptureResult(final boolean isEmpty) {
+		this.isEmpty = isEmpty;
+	}
+
+	/**
+	 * another constructor to provide the correct origin information, including
+	 * 
+	 * @param originDate the date at which the timeline should be positioned
+	 * @param unit the unit that should be used for this timeband
+	 * @param timebandId the timeband id
+	 */
+	public GetTimelineOriginForScriptureResult(final Long originDate, final Unit unit, final int timebandId) {
+		this.originDate = originDate;
+		this.suggestedTimeScale = unit;
+		this.timebandId = timebandId;
+		isEmpty = false;
+	}
+
+	/**
+	 * private constructor, used by GWT serialisation
+	 */
+	@SuppressWarnings("unused")
+	private GetTimelineOriginForScriptureResult() {
+
+	}
+
+	/**
+	 * @return the originDate
+	 */
+	public Long getOriginDate() {
+		return originDate;
+	}
+
+	/**
+	 * @return the suggestedTimeScale
+	 */
+	public Unit getSuggestedTimeScale() {
+		return suggestedTimeScale;
+	}
+
+	/**
+	 * gets the timeband id
+	 * 
+	 * @return timebandId
+	 */
+	public int getTimebandId() {
+		return timebandId;
+	}
+
+	/**
+	 * @return the isEmpty
+	 */
+	public boolean isEmpty() {
+		return isEmpty;
+	}
+
+	/**
+	 * @param isEmpty the isEmpty to set
+	 */
+	public void setEmpty(final boolean isEmpty) {
+		this.isEmpty = isEmpty;
+	}
+
+	/**
+	 * @param originDate the originDate to set
+	 */
+	public void setOriginDate(final Long originDate) {
+		this.originDate = originDate;
+	}
+
+	/**
+	 * @param unit the suggestedTimeScale to set
+	 */
+	public void setSuggestedTimeScale(final Unit unit) {
+		this.suggestedTimeScale = unit;
+	}
+
+	/**
+	 * @param timebandId the timebandId to set
+	 */
+	public void setTimebandId(final int timebandId) {
+		this.timebandId = timebandId;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetTimelineUISetupResult.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetTimelineUISetupResult.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/GetTimelineUISetupResult.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,53 @@
+package com.tyndalehouse.step.web.shared.result;
+
+import java.util.List;
+
+import net.customware.gwt.dispatch.shared.Result;
+
+import com.tyndalehouse.step.web.shared.common.timeline.TimelineBean;
+
+/**
+ * Response from a @see
+ * {@link com.tyndalehouse.step.web.shared.command.GetTimelineUISetupCommand}
+ * This contains details on how to set up each timeband, their units, etc.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class GetTimelineUISetupResult implements Result {
+
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -566447989637280143L;
+
+	/**
+	 * A list of timebands
+	 */
+	private List<TimelineBean> tlb;
+
+	/**
+	 * Default constructor made public
+	 */
+	public GetTimelineUISetupResult() {
+
+	}
+
+	/**
+	 * returns a list of timebands
+	 * 
+	 * @return a list of timeband beans
+	 */
+	public List<TimelineBean> getTimelines() {
+		return tlb;
+	}
+
+	/**
+	 * sets the list. made available for reflection
+	 * 
+	 * @param tlb the list of timeline beans
+	 */
+	public void setTimelines(final List<TimelineBean> tlb) {
+		this.tlb = tlb;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/InstallJswordModuleResult.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/InstallJswordModuleResult.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/result/InstallJswordModuleResult.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,54 @@
+package com.tyndalehouse.step.web.shared.result;
+
+import net.customware.gwt.dispatch.shared.Result;
+
+/**
+ * Response from a @see
+ * {@link com.tyndalehouse.step.web.shared.command.InstallJswordModuleCommand}
+ * indicating whether the installation was succesful
+ * 
+ * @author cjburrell
+ * 
+ */
+public class InstallJswordModuleResult implements Result {
+	/**
+	 * generated serial id
+	 */
+	private static final long serialVersionUID = -5063510082176727310L;
+
+	/**
+	 * true if installation was successful
+	 */
+	private boolean successful;
+
+	/**
+	 * Default constructor made public
+	 */
+	public InstallJswordModuleResult() {
+
+	}
+
+	/**
+	 * Constructor with the success flag passed in
+	 * 
+	 * @param successful true to indicate success
+	 */
+	public InstallJswordModuleResult(final boolean successful) {
+		this.successful = successful;
+
+	}
+
+	/**
+	 * @return the successful
+	 */
+	public boolean isSuccessful() {
+		return successful;
+	}
+
+	/**
+	 * @param successful the successful to set
+	 */
+	public void setSuccessful(final boolean successful) {
+		this.successful = successful;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Milestone.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Milestone.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Milestone.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,61 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+import java.io.Serializable;
+
+/**
+ * A marker in the OSIS xml to indicate a break in the normal flow of text.
+ * Usually editors layouts, I believe.
+ * 
+ * @author cjburrell
+ * 
+ */
+public class Milestone extends Text implements TextualElement, Serializable {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 6444472622836494795L;
+
+	/**
+	 * optional marker
+	 */
+	private String marker;
+
+	/**
+	 * Type of milestone, see OSIS details for clarifications
+	 */
+	private String type;
+
+	/**
+	 * Default constructor made public
+	 */
+	public Milestone() {
+	}
+
+	/**
+	 * @return the marker
+	 */
+	public String getMarker() {
+		return marker;
+	}
+
+	/**
+	 * @return the type
+	 */
+	public String getType() {
+		return type;
+	}
+
+	/**
+	 * @param marker the marker to set
+	 */
+	public void setMarker(final String marker) {
+		this.marker = marker;
+	}
+
+	/**
+	 * @param type the type to set
+	 */
+	public void setType(final String type) {
+		this.type = type;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Note.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Note.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Note.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,42 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+import java.io.Serializable;
+
+/**
+ * A logical representation of some OSIS xml. This bean is serialised and passed
+ * over the wire
+ * 
+ * @author cjburrell
+ * 
+ */
+public class Note extends Text implements TextualElement, Serializable {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 4592986819523938392L;
+
+	/**
+	 * The type of note
+	 */
+	private String type;
+
+	/**
+	 * Default constructor made public
+	 */
+	public Note() {
+	}
+
+	/**
+	 * @return the type
+	 */
+	public String getType() {
+		return type;
+	}
+
+	/**
+	 * @param type the type to set
+	 */
+	public void setType(final String type) {
+		this.type = type;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/OSISConstants.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/OSISConstants.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/OSISConstants.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,43 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+/**
+ * Some constants not defined in JSword
+ * 
+ * @author cjburrell
+ * 
+ */
+public final class OSISConstants {
+	/**
+	 * A marker in the text, for formatting purposes: TODO: check this and the
+	 * other two with online people
+	 */
+	public static final String MARKER = "marker";
+
+	/**
+	 * A milestone, between two portions of scripture
+	 */
+	public static final String MILESTONE = "milestone";
+
+	/**
+	 * A decision by the translator to make a change?
+	 */
+	public static final String TRANS_CHANGE = "transChange";
+
+	// public static final String LEMMA = "lemma";
+	// public static final String MORPH = "morph";
+	// public static final Object NOTE = "note";
+	// public static final String OSISID = "osisID";
+	// public static final String TITLE = "title";
+
+	// public static final String TYPE = "type";
+	// public static final String VERSE = "verse";
+	// public static final String WORD = "w";
+
+	/**
+	 * Making the constructor private
+	 */
+	private OSISConstants() {
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Passage.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Passage.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Passage.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,74 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Logical form of a passage
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class Passage implements TextualElement, Serializable {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -3926440372519158967L;
+
+	/**
+	 * List of verses/title throughout the passage
+	 */
+	private List<VerseContent> verseContent;
+
+	/**
+	 * making the constructor public and initialising list
+	 */
+	public Passage() {
+		verseContent = new ArrayList<VerseContent>();
+	}
+
+	/**
+	 * Adding a passage element, such as a {@link Verse} or a {@link Title}
+	 * 
+	 * @param vc a verse or a title
+	 */
+	public void addPassageElement(final VerseContent vc) {
+		verseContent.add(vc);
+	}
+
+	/**
+	 * returns the text representation of a passage. This is NOT performance
+	 * optimized and therefore should not be used more than once.
+	 * Non-optimization is due to the fact that we won't to reduce traffic over
+	 * the wire
+	 * 
+	 *TODO: this could be further optimized by not relying on strings in
+	 * versecontent being returned as strings
+	 * 
+	 * @return the passage in a string form.
+	 */
+	public String getText() {
+		final StringBuffer text = new StringBuffer(1024);
+		for (final VerseContent vc : verseContent) {
+			if (!(vc instanceof Title)) {
+				text.append(vc.getText());
+			}
+		}
+		return text.toString();
+	}
+
+	/**
+	 * @return the verseContent list of a combination of verses and titles
+	 */
+	public List<VerseContent> getVerseContent() {
+		return verseContent;
+	}
+
+	/**
+	 * @param verseContent the verseContent to set
+	 */
+	public void setVerseContent(final List<VerseContent> verseContent) {
+		this.verseContent = verseContent;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Text.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Text.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Text.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,51 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+import java.io.Serializable;
+
+/**
+ * The Text class, a wrapper for String
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class Text implements TextualElement, Serializable {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -7068301858306124428L;
+
+	/**
+	 * the string representing the portion of scripture for each OSIS element
+	 */
+	private String text;
+
+	/**
+	 * A simple text, default constructor made public
+	 */
+	public Text() {
+	}
+
+	/**
+	 * Initialising a text with a String
+	 * 
+	 * @param text text is the string representation of the #text element
+	 */
+	public Text(final String text) {
+		this.text = text;
+	}
+
+	/**
+	 * @return the text
+	 */
+	public String getText() {
+		return text;
+	}
+
+	/**
+	 * @param text the text to set
+	 */
+	public void setText(final String text) {
+		this.text = text;
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/TextualElement.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/TextualElement.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/TextualElement.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,18 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+/**
+ * Interface being applied to anything that can contains text (directly or
+ * indirectly)
+ * 
+ * @author CJBurrell
+ * 
+ */
+public interface TextualElement {
+
+	/**
+	 * returns the text
+	 * 
+	 * @return text to be returned
+	 */
+	String getText();
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Title.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Title.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Title.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,43 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+/**
+ * Title element in the OSIS as a POJO
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class Title extends Text implements VerseContent {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -4362500737203594954L;
+
+	/**
+	 * Type of title as defined in OSIS spec
+	 */
+	private String type;
+
+	/**
+	 * Making default constructor public
+	 */
+	public Title() {
+	}
+
+	/**
+	 * @return the type
+	 */
+	public String getType() {
+		return type;
+	}
+
+	/**
+	 * type of title
+	 * 
+	 * @param type title
+	 */
+	public void setType(final String type) {
+		this.type = type;
+
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/TransChange.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/TransChange.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/TransChange.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,41 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+import java.io.Serializable;
+
+/**
+ * TODO: check OSIS details and update documentation
+ * 
+ * @author cjburrell
+ * 
+ */
+public class TransChange extends Text implements TextualElement, Serializable {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = 4557607388014222750L;
+
+	/**
+	 * Type of trans change
+	 */
+	private String type;
+
+	/**
+	 * Default constructor made public
+	 */
+	public TransChange() {
+	}
+
+	/**
+	 * @return the type
+	 */
+	public String getType() {
+		return type;
+	}
+
+	/**
+	 * @param type the type to set
+	 */
+	public void setType(final String type) {
+		this.type = type;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Verse.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Verse.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Verse.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,92 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Logical representation of a verse from the OSIS
+ * 
+ * @author CJBurrell
+ * 
+ */
+public class Verse implements VerseContent, Serializable {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -7000973434382091156L;
+
+	/**
+	 * the OSIS key, for e.g. gen 1:1
+	 */
+	private String osisID;
+
+	/**
+	 * list of textual elements that are contained in this verse
+	 */
+	private List<TextualElement> verseContent;
+
+	/**
+	 * public constructor to create a logical form of a verse
+	 */
+	public Verse() {
+		verseContent = new ArrayList<TextualElement>();
+	}
+
+	/**
+	 * adds a textual element to the verse
+	 * 
+	 * @param te textual element
+	 */
+	public void addTextualElement(final TextualElement te) {
+		this.verseContent.add(te);
+	}
+
+	/**
+	 * @return the osisID
+	 */
+	public String getOsisID() {
+		return osisID;
+	}
+
+	/**
+	 * This method is not optimized for performance. It iterates through the
+	 * list each time it is required. The reason it is not optimized, is that it
+	 * should not be used except to display the text once.
+	 * 
+	 * Not storing the result of the concatenation enables us to have shorted
+	 * messages going across the wire
+	 * 
+	 * @return the concatenated text
+	 */
+	public String getText() {
+		final StringBuilder sb = new StringBuilder(128);
+		for (final TextualElement te : verseContent) {
+			if (!(te instanceof Note)) {
+				sb.append(te.getText());
+			}
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * @return the text
+	 */
+	public List<TextualElement> getVerseContent() {
+		return verseContent;
+	}
+
+	/**
+	 * @param osisID the osisID to set
+	 */
+	public void setOsisID(final String osisID) {
+		this.osisID = osisID;
+	}
+
+	/**
+	 * @param text the text to set
+	 */
+	public void setVerseContent(final List<TextualElement> text) {
+		this.verseContent = text;
+	}
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/VerseContent.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/VerseContent.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/VerseContent.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,12 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+/**
+ * This interfaces marks a verse or a title which are direct children of a
+ * passage
+ * 
+ * @author CJBurrell
+ * 
+ */
+public interface VerseContent extends TextualElement {
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Word.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Word.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/scripture/Word.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,137 @@
+package com.tyndalehouse.step.web.shared.scripture;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A Word is a portion of a verse from the Bible. It can be several words or
+ * just one. In some versions it is associated with a list of lemmas (strong
+ * numbers which link to the Strong Hebrew or Greek Dictionary), as well as a
+ * morphological code (morph) which is a coded form of the morphology of the
+ * word/set of words (i.e. grammar form and usage in the sentence)
+ * 
+ * @author cjburrell
+ * 
+ */
+public class Word extends Text implements TextualElement, Serializable {
+	/**
+	 * serial id
+	 */
+	private static final long serialVersionUID = -5750252359953024623L;
+
+	/**
+	 * An alternative word, such as a different language
+	 */
+	private String alternativeWord;
+
+	// TODO: FIX: this is a bug, we can have several lemmas or morphologies for
+	// one translated word
+	/**
+	 * a list of lemmas referring to a portion of text
+	 */
+	private List<String> lemma;
+
+	/**
+	 * A list of morphs referring to a portion of text. A morph is a coded
+	 * string indicating the grammar and form of the original word
+	 */
+	private List<String> morph;
+
+	/**
+	 * default constructor initialises internal lists
+	 */
+	public Word() {
+		lemma = new ArrayList<String>();
+		morph = new ArrayList<String>();
+	}
+
+	/**
+	 * Adds a new lemma to the Word
+	 * 
+	 * @param newLemma the lemma to set
+	 */
+	public void addLemma(final String newLemma) {
+		lemma.add(newLemma);
+	}
+
+	/**
+	 * Adds an array of lemmas to the Word
+	 * 
+	 * @param lemmas a list of lemmas
+	 */
+	public void addLemmas(final String[] lemmas) {
+		for (final String l : lemmas) {
+			this.lemma.add(l);
+		}
+	}
+
+	/**
+	 * Adds an array of morphs to the Word
+	 * 
+	 * @param morphs array of morphs to be associated with the Word (portion of
+	 *            a verse)
+	 */
+	public void addMorphs(final String[] morphs) {
+		for (final String m : morphs) {
+			this.morph.add(m);
+		}
+
+	}
+
+	/**
+	 * @return the alternativeWord
+	 */
+	public String getAlternativeWord() {
+		return alternativeWord;
+	}
+
+	/**
+	 * @return the lemma
+	 */
+	public List<String> getLemma() {
+		return lemma;
+	}
+
+	/**
+	 * @return the morph
+	 */
+	public List<String> getMorph() {
+		return morph;
+	}
+
+	/**
+	 * sets an alternative word (such as a hebrew original word)
+	 * 
+	 * @param alternativeWord a word equivalent, different language. For e.g.
+	 *            Hebrew word
+	 * 
+	 */
+	public void setAlternativeWord(final String alternativeWord) {
+		this.alternativeWord = alternativeWord;
+	}
+
+	/**
+	 * @param lemma the lemma to set
+	 */
+	public void setLemma(final List<String> lemma) {
+		this.lemma = lemma;
+	}
+
+	/**
+	 * @param morph the morph to set
+	 */
+	public void setMorph(final List<String> morph) {
+		this.morph = morph;
+	}
+
+	/**
+	 * Adding a morph to the Word
+	 * 
+	 * @param newMorph the morph to set
+	 */
+	public void setMorph(final String newMorph) {
+		morph.add(newMorph);
+	}
+
+}

Added: trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/timeline/Unit.java
===================================================================
--- trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/timeline/Unit.java	                        (rev 0)
+++ trunk/step-web-app/src/main/java/com/tyndalehouse/step/web/shared/timeline/Unit.java	2010-04-14 22:11:51 UTC (rev 120)
@@ -0,0 +1,100 @@
+package com.tyndalehouse.step.web.shared.timeline;
+
+/**
+ * Unit as used both on the server and on the ui This makes the correspondance
+ * between dates in milliseconds and their actual real dates
+ * 
+ * @author CJBurrell
+ * 
+ */
+public enum Unit {
+	/**
+	 * century
+	 */
+	CENTURY(10L * 10L * 365L * 24 * 3600 * 1000L, "yyyy G"),
+	/**
+	 * day
+	 */
+	DAY(24L * 3600L * 1000L, "dd MMM yyyy G"),
+	/**
+	 * decade
+	 */
+	DECADE(10L * 365L * 24 * 3600 * 1000L, "yyyy G"),
+	/**
+	 * hour
+	 */
+	HOUR(3600L * 1000L),
+	/**
+	 * 1000 years
+	 */
+	MILLENIUM(10L * 10L * 10L * 365L * 24 * 3600 * 1000L, "yyyy G"),
+	/**
+	 * a minute
+	 */
+	MINUTE(60L * 1000L),
+	/**
+	 * a month
+	 */
+	// CHECKSTYLE:OFF
+	MONTH((365L * 24L * 3600L * 1000L) / 12, "MMM yyyy G"),
+	// CHECKSTYLE:ON
+	/**
+	 * a second
+	 */
+	SECOND(1000L),
+	/**
+	 * a week
+	 * 
+	 */
+	WEEK(7L * 24L * 3600L * 1000L, "dd MMM yyyy G"),
+	/**
+	 * a year
+	 */
+	YEAR(365L * 24 * 3600 * 1000L, "yyyy G");
+
+	/**
+	 * format to be applied when displaying
+	 */
+	private final String format;
+	/**
+	 * length of unit in milliseconds
+	 */
+	private final long milliseconds;
+
+	/**
+	 * constructor to create a unit, with a default format of dd MMM YYYY G
+	 * 
+	 * @param milliseconds length of unit in milliseconds
+	 */
+	Unit(final long milliseconds) {
+		this(milliseconds, "dd MMM YYYY G");
+	}
+
+	/**
+	 * creates a unit enum
+	 * 
+	 * @param milliseconds length of unit in milliseconds
+	 * @param format format to be applied if different to default one of dd MMM
+	 *            YYYY G
+	 */
+	Unit(final long milliseconds, final String format) {
+		this.format = format;
+		this.milliseconds = milliseconds;
+	}
+
+	/**
+	 * returns the format to be used for the unit
+	 * 
+	 * @return the format format
+	 */
+	public String getFormat() {
+		return format;
+	}
+
+	/**
+	 * @return the value In Milliseconds of the length of the unit
+	 */
+	public long getMilliseconds() {
+		return milliseconds;
+	}
+}




More information about the Tynstep-svn mailing list