blob: 274fd550e934ee2ebdfec88cb645dfb9b88f4185 [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.place.shared;
import com.google.gwt.core.client.GWT;
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;
/**
* Monitors {@link PlaceChangeEvent}s and {@link com.google.gwt.user.client.History} events and keep them in sync.
*/
public class PlaceHistoryHandler {
private static final Logger log = Logger.getLogger(PlaceHistoryHandler.class.getName());
/**
* Default implementation of {@link Historian}, based on {@link History}.
*/
public static class DefaultHistorian implements 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);
}
}
/**
* Optional delegate in charge of History related events. Provides nice
* isolation for unit testing, and allows pre- or post-processing of tokens.
*/
public interface Historian {
HandlerRegistration addValueChangeHandler(
ValueChangeHandler<String> valueChangeHandler);
String getToken();
void newItem(String token, boolean issueEvent);
}
private final Historian historian;
private final PlaceHistoryMapper mapper;
private PlaceController placeController;
private Place defaultPlace = Place.NOWHERE;
/**
* Create a new PlaceHistoryHandler with a {@link DefaultHistorian}.
* The DefaultHistorian is created via a call to GWT.create(), so an
* alternative default implementation can be provided through
* &lt;replace-with> rules in a gwt.xml file.
*/
public PlaceHistoryHandler(PlaceHistoryMapper mapper) {
this(mapper, (Historian) GWT.create(DefaultHistorian.class));
}
/**
* Create a new PlaceHistoryHandler.
*/
public PlaceHistoryHandler(PlaceHistoryMapper mapper, Historian historian) {
this.mapper = mapper;
this.historian = historian;
}
public void handleCurrentHistory() {
handleHistoryToken(historian.getToken());
}
public HandlerRegistration register(PlaceController placeController,
EventBus eventBus, Place defaultPlace) {
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() {
PlaceHistoryHandler.this.defaultPlace = Place.NOWHERE;
PlaceHistoryHandler.this.placeController = null;
placeReg.removeHandler();
historyReg.removeHandler();
}
};
}
/**
* Visible for testing.
*/
Logger log() {
return log;
}
private void handleHistoryToken(String token) {
Place newPlace = null;
if ("".equals(token)) {
newPlace = defaultPlace;
}
if (newPlace == null) {
newPlace = mapper.getPlace(token);
}
if (newPlace == null) {
log().warning("Unrecognized history token: " + token);
newPlace = defaultPlace;
}
placeController.goTo(newPlace);
}
private String tokenForPlace(Place newPlace) {
if (defaultPlace.equals(newPlace)) {
return "";
}
String token = mapper.getToken(newPlace);
if (token != null) {
return token;
}
log().warning("Place not mapped to a token: " + newPlace);
return "";
}
}