001: /*
002: * Copyright 2007 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:
021: import java.util.ArrayList;
022:
023: /**
024: * A simplified, browser-safe timer class. This class serves the same purpose as
025: * java.util.Timer, but is simplified because of the single-threaded
026: * environment.
027: *
028: * To schedule a timer, simply create a subclass of it (overriding {@link #run})
029: * and call {@link #schedule} or {@link #scheduleRepeating}.
030: *
031: * <p>
032: * <h3>Example</h3>
033: * {@example com.google.gwt.examples.TimerExample}
034: * </p>
035: */
036: public abstract class Timer {
037:
038: private static ArrayList<Timer> timers = new ArrayList<Timer>();
039:
040: static {
041: hookWindowClosing();
042: }
043:
044: private static native void clearInterval(int id) /*-{
045: $wnd.clearInterval(id);
046: }-*/;
047:
048: private static native void clearTimeout(int id) /*-{
049: $wnd.clearTimeout(id);
050: }-*/;
051:
052: private static native int createInterval(Timer timer, int period) /*-{
053: return $wnd.setInterval(
054: function() { timer.@com.google.gwt.user.client.Timer::fire()(); },
055: period);
056: }-*/;
057:
058: private static native int createTimeout(Timer timer, int delay) /*-{
059: return $wnd.setTimeout(
060: function() { timer.@com.google.gwt.user.client.Timer::fire()(); },
061: delay);
062: }-*/;
063:
064: private static void hookWindowClosing() {
065: // Catch the window closing event.
066: Window.addWindowCloseListener(new WindowCloseListener() {
067: public void onWindowClosed() {
068: // When the window is closing, cancel all extant timers. This ensures
069: // that no leftover timers can cause memory leaks by leaving links from
070: // the window's timeout closures back into Java objects.
071: while (timers.size() > 0) {
072: timers.get(0).cancel();
073: }
074: }
075:
076: public String onWindowClosing() {
077: return null;
078: }
079: });
080: }
081:
082: private boolean isRepeating;
083:
084: private int timerId;
085:
086: /**
087: * Cancels this timer.
088: */
089: public void cancel() {
090: if (isRepeating) {
091: clearInterval(timerId);
092: } else {
093: clearTimeout(timerId);
094: }
095: timers.remove(this );
096: }
097:
098: /**
099: * This method will be called when a timer fires. Override it to implement the
100: * timer's logic.
101: */
102: public abstract void run();
103:
104: /**
105: * Schedules a timer to elapse in the future.
106: *
107: * @param delayMillis how long to wait before the timer elapses, in
108: * milliseconds
109: */
110: public void schedule(int delayMillis) {
111: if (delayMillis <= 0) {
112: throw new IllegalArgumentException("must be positive");
113: }
114: cancel();
115: isRepeating = false;
116: timerId = createTimeout(this , delayMillis);
117: timers.add(this );
118: }
119:
120: /**
121: * Schedules a timer that elapses repeatedly.
122: *
123: * @param periodMillis how long to wait before the timer elapses, in
124: * milliseconds, between each repetition
125: */
126: public void scheduleRepeating(int periodMillis) {
127: if (periodMillis <= 0) {
128: throw new IllegalArgumentException("must be positive");
129: }
130: cancel();
131: isRepeating = true;
132: timerId = createInterval(this , periodMillis);
133: timers.add(this );
134: }
135:
136: /*
137: * Called by native code when this timer fires.
138: */
139: final void fire() {
140: UncaughtExceptionHandler handler = GWT
141: .getUncaughtExceptionHandler();
142: if (handler != null) {
143: fireAndCatch(handler);
144: } else {
145: fireImpl();
146: }
147: }
148:
149: private void fireAndCatch(UncaughtExceptionHandler handler) {
150: try {
151: fireImpl();
152: } catch (Throwable e) {
153: handler.onUncaughtException(e);
154: }
155: }
156:
157: private void fireImpl() {
158: // If this is a one-shot timer, remove it from the timer list. This will
159: // allow it to be garbage collected.
160: if (!isRepeating) {
161: timers.remove(this );
162: }
163:
164: // Run the timer's code.
165: run();
166: }
167: }
|