/*
* Ext GWT - Ext for GWT
* Copyright(c) 2007-2009, Ext JS, LLC.
* licensing@extjs.com
*
* http://extjs.com/license
*/
package com.extjs.gxt.ui.client.mvc;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import com.extjs.gxt.ui.client.core.FastMap;
import com.extjs.gxt.ui.client.event.BaseEvent;
import com.extjs.gxt.ui.client.event.BaseObservable;
import com.extjs.gxt.ui.client.event.EventType;
import com.extjs.gxt.ui.client.event.MvcEvent;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.user.client.History;
/**
* Dispatchers are responsible for dispatching application events to
* controllers.
*
* <dl>
* <dt><b>Events:</b></dt>
*
* <dd><b>Dispatcher.BeforeDispatch</b> : MvcEvent(dispatcher, appEvent)<br>
* <div>Fires before an event is dispatched. Listeners can cancel the action by
* calling {@link BaseEvent#setCancelled(boolean)}.</div>
* <ul>
* <li>dispatcher : this</li>
* <li>appEvent : the application event</li>
* </ul>
* </dd>
*
* <dd><b>Dispatcher.AfterDispatch</b> : MvcEvent(dispatcher, appEvent)<br>
* <div>Fires after an event has been dispatched.</div>
* <ul>
* <li>dispatcher : this</li>
* <li>appEvent : the application event</li>
* </ul>
* </dd>
*
* </dl>
*
* @see DispatcherListener
*/
public class Dispatcher extends BaseObservable {
/**
* Fires before an event is dispatched.
*/
public static final EventType BeforeDispatch = new EventType();
/**
* Fires after an event has been dispatched.
*/
public static final EventType AfterDispatch = new EventType();
private static Dispatcher instance = new Dispatcher();
/**
* Forwards an application event to the dispatcher.
*
* @param event the application event
*/
public static void forwardEvent(AppEvent event) {
instance.dispatch(event);
}
/**
* Creates and forwards an application event to the dispatcher.
*
* @param eventType the application event type
*/
public static void forwardEvent(EventType eventType) {
instance.dispatch(eventType);
}
/**
* Creates and forwards an application event to the dispatcher.
*
* @param eventType the application event type
* @param data the event data
*/
public static void forwardEvent(EventType eventType, Object data) {
instance.dispatch(new AppEvent(eventType, data));
}
/**
* Creates and forwards an application event to the dispatcher.
*
* @param eventType the application event type
* @param data the event data
* @param historyEvent true to mark event as a history event
*/
public static void forwardEvent(EventType eventType, Object data, boolean historyEvent) {
AppEvent ae = new AppEvent(eventType, data);
ae.setHistoryEvent(historyEvent);
instance.dispatch(ae);
}
/**
* Returns the singleton instance.
*
* @return the dispatcher
*/
public static Dispatcher get() {
return instance;
}
private Map<String, AppEvent> history;
private List<Controller> controllers;
private Dispatcher() {
controllers = new ArrayList<Controller>();
history = new FastMap<AppEvent>();
History.addValueChangeHandler(new ValueChangeHandler<String>() {
public void onValueChange(ValueChangeEvent<String> event) {
String historyToken = event.getValue();
if (history.containsKey(historyToken)) {
dispatch(history.get(historyToken), false);
}
}
});
}
/**
* Adds a controller.
*
* @param controller the controller to be added
*/
public void addController(Controller controller) {
if (!controllers.contains(controller)) {
controllers.add(controller);
}
}
/**
* Adds a listener to receive dispatch events.
*
* @param listener the listener to add
*/
public void addDispatcherListener(DispatcherListener listener) {
addListener(BeforeDispatch, listener);
addListener(AfterDispatch, listener);
}
/**
* The dispatcher will query its controllers and pass the application event to any
* controllers that can handle the particular event type.
*
* @param event the application event
*/
public void dispatch(AppEvent event) {
dispatch(event, event.isHistoryEvent());
}
/**
* The dispatcher will query its controllers and pass the application event to
* controllers that can handle the particular event type.
*
* @param type the event type
*/
public void dispatch(EventType type) {
dispatch(new AppEvent(type));
}
/**
* The dispatcher will query its controllers and pass the application event to
* controllers that can handle the particular event type.
*
* @param type the event type
* @param data the app event data
*/
public void dispatch(EventType type, Object data) {
dispatch(new AppEvent(type, data));
}
/**
* Returns all controllers.
*
* @return the list of controllers
*/
public List<Controller> getControllers() {
return controllers;
}
/**
* Returns the dispatcher's history cache.
*
* @return the history
*/
public Map<String, AppEvent> getHistory() {
return history;
}
/**
* Removes a controller.
*
* @param controller the controller to be removed
*/
public void removeController(Controller controller) {
controllers.remove(controller);
}
/**
* Removes a previously added listener.
*
* @param listener the listener to be removed
*/
public void removeDispatcherListener(DispatcherListener listener) {
removeListener(BeforeDispatch, listener);
removeListener(AfterDispatch, listener);
}
private void dispatch(AppEvent event, boolean createhistory) {
MvcEvent e = new MvcEvent(this, event);
e.setAppEvent(event);
if (fireEvent(BeforeDispatch, e)) {
for (Controller controller : controllers) {
if (controller.canHandle(event)) {
if (!controller.initialized) {
controller.initialized = true;
controller.initialize();
}
controller.handleEvent(event);
}
}
fireEvent(AfterDispatch, e);
}
if (createhistory && event.isHistoryEvent()) {
String token = event.getToken();
if (token == null) {
token = "" + new Date().getTime();
}
history.put(token, event);
History.newItem(token, false);
}
}
}