001 /*
002 * Copyright 2006 Google Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005 * use this file except in compliance with the License. You may obtain a copy of
006 * the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013 * License for the specific language governing permissions and limitations under
014 * the License.
015 */
016 package com.google.gwt.user.client;
017
018 import com.google.gwt.core.client.GWT;
019 import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
020 import com.google.gwt.user.client.impl.HistoryImpl;
021
022 import java.util.Iterator;
023 import java.util.Vector;
024
025 /**
026 * This class allows you to interact with the browser's history stack. Each
027 * "item" on the stack is represented by a single string, referred to as a
028 * "token". You can create new history items (which have a token associated with
029 * them when they are created), and you can programmatically force the current
030 * history to move back or forward.
031 *
032 * <p>
033 * In order to receive notification of user-directed changes to the current
034 * history item, implement the
035 * {@link com.google.gwt.user.client.HistoryListener} interface and attach it
036 * via {@link #addHistoryListener}.
037 * </p>
038 *
039 * <p>
040 * Example: {@link com.google.gwt.examples.HistoryExample code}
041 * </p>
042 */
043 public class History {
044
045 private static Vector historyListeners = new Vector();
046 private static HistoryImpl impl;
047
048 static {
049 impl = (HistoryImpl) GWT.create(HistoryImpl.class);
050 if (!impl.init()) {
051 // Set impl to null as a flag to no-op future calls.
052 impl = null;
053
054 // Tell the user.
055 GWT.log("Unable to initialize the history subsystem; did you "
056 + "include the history frame in your host page? Try "
057 + "<iframe id='__gwt_historyFrame' style='width:0;height:0;border:0'>"
058 + "</iframe>", null);
059 }
060 }
061
062 /**
063 * Adds a listener to be informed of changes to the browser's history stack.
064 *
065 * @param listener the listener to be added
066 */
067 public static void addHistoryListener(HistoryListener listener) {
068 historyListeners.add(listener);
069 }
070
071 /**
072 * Programmatic equivalent to the user pressing the browser's 'back' button.
073 */
074 public static native void back() /*-{
075 $wnd.history.back();
076 }-*/;
077
078 /**
079 * Programmatic equivalent to the user pressing the browser's 'forward'
080 * button.
081 */
082 public static native void forward() /*-{
083 $wnd.history.forward();
084 }-*/;
085
086 /**
087 * Gets the current history token. The listener will not receive an
088 * onHistoryChanged() event for the initial token; requiring that an
089 * application request the token explicitly on startup gives it an opportunity
090 * to run different initialization code in the presence or absence of an
091 * initial token.
092 *
093 * @return the initial token, or the empty string if none is present.
094 */
095 public static String getToken() {
096 return impl != null ? impl.getToken() : "";
097 }
098
099 /**
100 * Adds a new browser history entry. In hosted mode, the 'back' and 'forward'
101 * actions are accessible via the standard Alt-Left and Alt-Right keystrokes.
102 * Calling this method will cause {@link #onHistoryChanged} to be called as
103 * well.
104 *
105 * @param title the title that should appear in the history menu for this
106 * history item.
107 */
108 public static void newItem(String historyToken) {
109 if (impl != null) {
110 impl.newItem(historyToken);
111 }
112 }
113
114 public static void onHistoryChanged(String historyToken) {
115 UncaughtExceptionHandler handler = GWT.getUncaughtExceptionHandler();
116 if (handler != null)
117 fireHistoryChangedAndCatch(historyToken, handler);
118 else
119 fireHistoryChangedImpl(historyToken);
120 }
121
122 private static void fireHistoryChangedAndCatch(String historyToken,
123 UncaughtExceptionHandler handler) {
124 try {
125 fireHistoryChangedImpl(historyToken);
126 } catch (Throwable e) {
127 handler.onUncaughtException(e);
128 }
129 }
130
131 private static void fireHistoryChangedImpl(String historyToken) {
132 for (Iterator it = historyListeners.iterator(); it.hasNext();) {
133 HistoryListener listener = (HistoryListener) it.next();
134 listener.onHistoryChanged(historyToken);
135 }
136 }
137
138 /**
139 * Removes a history listener.
140 *
141 * @param listener the listener to be removed
142 */
143 public static void removeHistoryListener(HistoryListener listener) {
144 historyListeners.remove(listener);
145 }
146 }