blob: 57024670f4ad248cfeb9e86bfedba535d9c22780 [file] [log] [blame]
/*
* Copyright 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.app.place;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.History;
import java.util.logging.Logger;
/**
* Abstract implementation of {@link PlaceHistoryHandler}.
*
* @param <F> the factory type
*/
public abstract class AbstractPlaceHistoryHandler<F> implements
PlaceHistoryHandlerWithFactory<F> {
private static final Logger log = Logger.getLogger(AbstractPlaceHistoryHandler.class.getName());
/**
* Return value for
* {@link AbstractPlaceHistoryHandler#getPrefixAndToken(Place)}.
*/
public static class PrefixAndToken {
public final String prefix;
public final String token;
public PrefixAndToken(String prefix, String token) {
super();
this.prefix = prefix;
this.token = token;
}
@Override
public String toString() {
return prefix + ":" + token;
}
}
/**
* Isolates us from History, for testing.
*/
protected interface Historian {
HandlerRegistration addValueChangeHandler(
ValueChangeHandler<String> valueChangeHandler);
String getToken();
void newItem(String token, boolean issueEvent);
}
private final Historian historian;
protected F factory;
protected PlaceController placeController;
private Place defaultPlace = Place.NOWHERE;
protected AbstractPlaceHistoryHandler() {
this(new Historian() {
public HandlerRegistration addValueChangeHandler(
ValueChangeHandler<String> valueChangeHandler) {
return History.addValueChangeHandler(valueChangeHandler);
}
public String getToken() {
return History.getToken();
}
public void newItem(String token, boolean issueEvent) {
History.newItem(token, issueEvent);
}
});
}
protected AbstractPlaceHistoryHandler(Historian historian) {
this.historian = historian;
}
public void handleCurrentHistory() {
handleHistoryToken(historian.getToken());
}
public HandlerRegistration register(PlaceController placeController,
EventBus eventBus, Place defaultPlace) {
assert factory != null : "No factory was set";
this.placeController = placeController;
this.defaultPlace = defaultPlace;
final HandlerRegistration placeReg = eventBus.addHandler(
PlaceChangeEvent.TYPE, new PlaceChangeEvent.Handler() {
public void onPlaceChange(PlaceChangeEvent event) {
Place newPlace = event.getNewPlace();
historian.newItem(tokenForPlace(newPlace), false);
}
});
final HandlerRegistration historyReg = historian.addValueChangeHandler(new ValueChangeHandler<String>() {
public void onValueChange(ValueChangeEvent<String> event) {
String token = event.getValue();
handleHistoryToken(token);
}
});
return new HandlerRegistration() {
public void removeHandler() {
AbstractPlaceHistoryHandler.this.defaultPlace = Place.NOWHERE;
AbstractPlaceHistoryHandler.this.placeController = null;
AbstractPlaceHistoryHandler.this.factory = null;
placeReg.removeHandler();
historyReg.removeHandler();
}
};
}
public void setFactory(F factory) {
this.factory = factory;
}
/**
* @param newPlace what needs tokenizing
* @return the token, or null
*/
protected abstract PrefixAndToken getPrefixAndToken(Place newPlace);
/**
* @param prefix the prefix found on the history token
* @return the PlaceTokenizer registered with that token, or null
*/
protected abstract PlaceTokenizer<?> getTokenizer(String prefix);
/**
* Visible for testing.
*/
Logger log() {
return log;
}
private void handleHistoryToken(String token) {
Place newPlace = null;
if ("".equals(token)) {
newPlace = defaultPlace;
}
if (newPlace == null) {
int colonAt = token.indexOf(':');
if (colonAt > -1) {
String initial = token.substring(0, colonAt);
String rest = token.substring(colonAt + 1);
PlaceTokenizer<?> tokenizer = getTokenizer(initial);
if (tokenizer != null) {
newPlace = tokenizer.getPlace(rest);
}
}
}
if (newPlace == null) {
log().warning("Unrecognized history token: " + token);
newPlace = defaultPlace;
}
placeController.goTo(newPlace);
}
private String tokenForPlace(Place newPlace) {
if (defaultPlace.equals(newPlace)) {
return "";
}
PrefixAndToken token = getPrefixAndToken(newPlace);
if (token != null) {
return token.toString();
}
log().warning("Unregistered place type : " + newPlace);
return "";
}
}