/* * 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.shared.HandlerRegistration; import com.google.gwt.user.client.Window; import com.google.gwt.user.client.Window.ClosingEvent; import com.google.gwt.user.client.Window.ClosingHandler; import com.google.web.bindery.event.shared.EventBus; import java.util.logging.Logger; /** * In charge of the user's location in the app. */ public class PlaceController { /** * Default implementation of {@link Delegate}, based on {@link Window}. */ public static class DefaultDelegate implements Delegate { public HandlerRegistration addWindowClosingHandler(ClosingHandler handler) { return Window.addWindowClosingHandler(handler); } public boolean confirm(String message) { return Window.confirm(message); } } /** * Optional delegate in charge of Window-related events. Provides nice * isolation for unit testing, and allows customization of confirmation * handling. */ public interface Delegate { /** * Adds a {@link ClosingHandler} to the Delegate. * * @param handler a {@link ClosingHandler} instance * @return a {@link HandlerRegistration} instance */ HandlerRegistration addWindowClosingHandler(ClosingHandler handler); /** * Called to confirm a window closing event. * * @param message a warning message * @return true to allow the window closing */ boolean confirm(String message); } private static final Logger log = Logger.getLogger(PlaceController.class.getName()); private final EventBus eventBus; private final Delegate delegate; private Place where = Place.NOWHERE; /** * Legacy method tied to the old location for {@link EventBus}. * * @deprecated use {@link #PlaceController(EventBus)} */ @Deprecated public PlaceController(com.google.gwt.event.shared.EventBus eventBus) { this((EventBus) eventBus); } /** * Legacy method tied to the old location for {@link EventBus}. * * @deprecated use {@link #PlaceController(EventBus, Delegate)} */ @Deprecated public PlaceController(com.google.gwt.event.shared.EventBus eventBus, Delegate delegate) { this((EventBus) eventBus, delegate); } /** * Create a new PlaceController with a {@link DefaultDelegate}. The * DefaultDelegate is created via a call to GWT.create(), so an alternative * default implementation can be provided through <replace-with> rules * in a {@code .gwt.xml} file. * * @param eventBus the {@link EventBus} */ public PlaceController(EventBus eventBus) { this(eventBus, (Delegate) GWT.create(DefaultDelegate.class)); } /** * Create a new PlaceController. * * @param eventBus the {@link EventBus} * @param delegate the {@link Delegate} in charge of Window-related events */ public PlaceController(EventBus eventBus, Delegate delegate) { this.eventBus = eventBus; this.delegate = delegate; delegate.addWindowClosingHandler(new ClosingHandler() { public void onWindowClosing(ClosingEvent event) { String warning = maybeGoTo(Place.NOWHERE); if (warning != null) { event.setMessage(warning); } } }); } /** * Returns the current place. * * @return a {@link Place} instance */ public Place getWhere() { return where; } /** * Request a change to a new place. It is not a given that we'll actually get * there. First a {@link PlaceChangeRequestEvent} will be posted to the event * bus. If any receivers post a warning message to that event, it will be * presented to the user via {@link Delegate#confirm(String)} (which is * typically a call to {@link Window#confirm(String)}). If she cancels, the * current location will not change. Otherwise, the location changes and a * {@link PlaceChangeEvent} is posted announcing the new place. * * @param newPlace a {@link Place} instance */ public void goTo(Place newPlace) { log().fine("goTo: " + newPlace); if (getWhere().equals(newPlace)) { log().fine("Asked to return to the same place: " + newPlace); return; } String warning = maybeGoTo(newPlace); if (warning == null || delegate.confirm(warning)) { where = newPlace; eventBus.fireEvent(new PlaceChangeEvent(newPlace)); } } /** * Visible for testing. */ Logger log() { return log; } private String maybeGoTo(Place newPlace) { PlaceChangeRequestEvent willChange = new PlaceChangeRequestEvent(newPlace); eventBus.fireEvent(willChange); String warning = willChange.getWarning(); return warning; } }