History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/javax/swing/Timer.java (1 of 18352 files). Show all

Unified · Split

java/pkg/javax/swing/Timer.java+645−0
@@ -0,0 +1,645 @@
1+/*
2+ * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+
27+
28+package javax.swing;
29+
30+
31+
32+import java.util.*;
33+import java.util.concurrent.atomic.AtomicBoolean;
34+import java.util.concurrent.locks.*;
35+import java.awt.*;
36+import java.awt.event.*;
37+import java.io.Serializable;
38+import java.io.*;
39+import java.security.AccessControlContext;
40+import java.security.AccessController;
41+import java.security.PrivilegedAction;
42+import javax.swing.event.EventListenerList;
43+
44+
45+
46+/**
47+ * Fires one or more {@code ActionEvent}s at specified
48+ * intervals. An example use is an animation object that uses a
49+ * <code>Timer</code> as the trigger for drawing its frames.
50+ *<p>
51+ * Setting up a timer
52+ * involves creating a <code>Timer</code> object,
53+ * registering one or more action listeners on it,
54+ * and starting the timer using
55+ * the <code>start</code> method.
56+ * For example,
57+ * the following code creates and starts a timer
58+ * that fires an action event once per second
59+ * (as specified by the first argument to the <code>Timer</code> constructor).
60+ * The second argument to the <code>Timer</code> constructor
61+ * specifies a listener to receive the timer's action events.
62+ *
63+ *<pre>
64+ * int delay = 1000; //milliseconds
65+ * ActionListener taskPerformer = new ActionListener() {
66+ * public void actionPerformed(ActionEvent evt) {
67+ * <em>//...Perform a task...</em>
68+ * }
69+ * };
70+ * new Timer(delay, taskPerformer).start();</pre>
71+ *
72+ * <p>
73+ * {@code Timers} are constructed by specifying both a delay parameter
74+ * and an {@code ActionListener}. The delay parameter is used
75+ * to set both the initial delay and the delay between event
76+ * firing, in milliseconds. Once the timer has been started,
77+ * it waits for the initial delay before firing its
78+ * first <code>ActionEvent</code> to registered listeners.
79+ * After this first event, it continues to fire events
80+ * every time the between-event delay has elapsed, until it
81+ * is stopped.
82+ * <p>
83+ * After construction, the initial delay and the between-event
84+ * delay can be changed independently, and additional
85+ * <code>ActionListeners</code> may be added.
86+ * <p>
87+ * If you want the timer to fire only the first time and then stop,
88+ * invoke <code>setRepeats(false)</code> on the timer.
89+ * <p>
90+ * Although all <code>Timer</code>s perform their waiting
91+ * using a single, shared thread
92+ * (created by the first <code>Timer</code> object that executes),
93+ * the action event handlers for <code>Timer</code>s
94+ * execute on another thread -- the event-dispatching thread.
95+ * This means that the action handlers for <code>Timer</code>s
96+ * can safely perform operations on Swing components.
97+ * However, it also means that the handlers must execute quickly
98+ * to keep the GUI responsive.
99+ *
100+ * <p>
101+ * In v 1.3, another <code>Timer</code> class was added
102+ * to the Java platform: <code>java.util.Timer</code>.
103+ * Both it and <code>javax.swing.Timer</code>
104+ * provide the same basic functionality,
105+ * but <code>java.util.Timer</code>
106+ * is more general and has more features.
107+ * The <code>javax.swing.Timer</code> has two features
108+ * that can make it a little easier to use with GUIs.
109+ * First, its event handling metaphor is familiar to GUI programmers
110+ * and can make dealing with the event-dispatching thread
111+ * a bit simpler.
112+ * Second, its
113+ * automatic thread sharing means that you don't have to
114+ * take special steps to avoid spawning
115+ * too many threads.
116+ * Instead, your timer uses the same thread
117+ * used to make cursors blink,
118+ * tool tips appear,
119+ * and so on.
120+ *
121+ * <p>
122+ * You can find further documentation
123+ * and several examples of using timers by visiting
124+ * <a href="http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html"
125+ * target = "_top">How to Use Timers</a>,
126+ * a section in <em>The Java Tutorial.</em>
127+ * For more examples and help in choosing between
128+ * this <code>Timer</code> class and
129+ * <code>java.util.Timer</code>,
130+ * see
131+ * <a href="http://java.sun.com/products/jfc/tsc/articles/timer/"
132+ * target="_top">Using Timers in Swing Applications</a>,
133+ * an article in <em>The Swing Connection.</em>
134+ * <p>
135+ * <strong>Warning:</strong>
136+ * Serialized objects of this class will not be compatible with
137+ * future Swing releases. The current serialization support is
138+ * appropriate for short term storage or RMI between applications running
139+ * the same version of Swing. As of 1.4, support for long term storage
140+ * of all JavaBeans<sup><font size="-2">TM</font></sup>
141+ * has been added to the <code>java.beans</code> package.
142+ * Please see {@link java.beans.XMLEncoder}.
143+ *
144+ * @see java.util.Timer <code>java.util.Timer</code>
145+ *
146+ *
147+ * @author Dave Moore
148+ */
149+public class Timer implements Serializable
150+{
151+ /*
152+ * NOTE: all fields need to be handled in readResolve
153+ */
154+
155+ protected EventListenerList listenerList = new EventListenerList();
156+
157+ // The following field strives to maintain the following:
158+ // If coalesce is true, only allow one Runnable to be queued on the
159+ // EventQueue and be pending (ie in the process of notifying the
160+ // ActionListener). If we didn't do this it would allow for a
161+ // situation where the app is taking too long to process the
162+ // actionPerformed, and thus we'ld end up queing a bunch of Runnables
163+ // and the app would never return: not good. This of course implies
164+ // you can get dropped events, but such is life.
165+ // notify is used to indicate if the ActionListener can be notified, when
166+ // the Runnable is processed if this is true it will notify the listeners.
167+ // notify is set to true when the Timer fires and the Runnable is queued.
168+ // It will be set to false after notifying the listeners (if coalesce is
169+ // true) or if the developer invokes stop.
170+ private transient final AtomicBoolean notify = new AtomicBoolean(false);
171+
172+ private volatile int initialDelay, delay;
173+ private volatile boolean repeats = true, coalesce = true;
174+
175+ private transient final Runnable doPostEvent;
176+
177+ private static volatile boolean logTimers;
178+
179+ private transient final Lock lock = new ReentrantLock();
180+
181+ // This field is maintained by TimerQueue.
182+ // eventQueued can also be reset by the TimerQueue, but will only ever
183+ // happen in applet case when TimerQueues thread is destroyed.
184+ // access to this field is synchronized on getLock() lock.
185+ transient TimerQueue.DelayedTimer delayedTimer = null;
186+
187+ private volatile String actionCommand;
188+
189+ /**
190+ * Creates a {@code Timer} and initializes both the initial delay and
191+ * between-event delay to {@code delay} milliseconds. If {@code delay}
192+ * is less than or equal to zero, the timer fires as soon as it
193+ * is started. If <code>listener</code> is not <code>null</code>,
194+ * it's registered as an action listener on the timer.
195+ *
196+ * @param delay milliseconds for the initial and between-event delay
197+ * @param listener an initial listener; can be <code>null</code>
198+ *
199+ * @see #addActionListener
200+ * @see #setInitialDelay
201+ * @see #setRepeats
202+ */
203+ public Timer(int delay, ActionListener listener) {
204+ super();
205+ this.delay = delay;
206+ this.initialDelay = delay;
207+
208+ doPostEvent = new DoPostEvent();
209+
210+ if (listener != null) {
211+ addActionListener(listener);
212+ }
213+ }
214+
215+ /*
216+ * The timer's AccessControlContext.
217+ */
218+ private transient volatile AccessControlContext acc =
219+ AccessController.getContext();
220+
221+ /**
222+ * Returns the acc this timer was constructed with.
223+ */
224+ final AccessControlContext getAccessControlContext() {
225+ if (acc == null) {
226+ throw new SecurityException(
227+ "Timer is missing AccessControlContext");
228+ }
229+ return acc;
230+ }
231+
232+ /**
233+ * DoPostEvent is a runnable class that fires actionEvents to
234+ * the listeners on the EventDispatchThread, via invokeLater.
235+ * @see Timer#post
236+ */
237+ class DoPostEvent implements Runnable
238+ {
239+ public void run() {
240+ if (logTimers) {
241+ System.out.println("Timer ringing: " + Timer.this);
242+ }
243+ if(notify.get()) {
244+ fireActionPerformed(new ActionEvent(Timer.this, 0, getActionCommand(),
245+ System.currentTimeMillis(),
246+ 0));
247+ if (coalesce) {
248+ cancelEvent();
249+ }
250+ }
251+ }
252+
253+ Timer getTimer() {
254+ return Timer.this;
255+ }
256+ }
257+
258+ /**
259+ * Adds an action listener to the <code>Timer</code>.
260+ *
261+ * @param listener the listener to add
262+ *
263+ * @see #Timer
264+ */
265+ public void addActionListener(ActionListener listener) {
266+ listenerList.add(ActionListener.class, listener);
267+ }
268+
269+
270+ /**
271+ * Removes the specified action listener from the <code>Timer</code>.
272+ *
273+ * @param listener the listener to remove
274+ */
275+ public void removeActionListener(ActionListener listener) {
276+ listenerList.remove(ActionListener.class, listener);
277+ }
278+
279+
280+ /**
281+ * Returns an array of all the action listeners registered
282+ * on this timer.
283+ *
284+ * @return all of the timer's <code>ActionListener</code>s or an empty
285+ * array if no action listeners are currently registered
286+ *
287+ * @see #addActionListener
288+ * @see #removeActionListener
289+ *
290+ * @since 1.4
291+ */
292+ public ActionListener[] getActionListeners() {
293+ return listenerList.getListeners(ActionListener.class);
294+ }
295+
296+
297+ /**
298+ * Notifies all listeners that have registered interest for
299+ * notification on this event type.
300+ *
301+ * @param e the action event to fire
302+ * @see EventListenerList
303+ */
304+ protected void fireActionPerformed(ActionEvent e) {
305+ // Guaranteed to return a non-null array
306+ Object[] listeners = listenerList.getListenerList();
307+
308+ // Process the listeners last to first, notifying
309+ // those that are interested in this event
310+ for (int i=listeners.length-2; i>=0; i-=2) {
311+ if (listeners[i]==ActionListener.class) {
312+ ((ActionListener)listeners[i+1]).actionPerformed(e);
313+ }
314+ }
315+ }
316+
317+ /**
318+ * Returns an array of all the objects currently registered as
319+ * <code><em>Foo</em>Listener</code>s
320+ * upon this <code>Timer</code>.
321+ * <code><em>Foo</em>Listener</code>s
322+ * are registered using the <code>add<em>Foo</em>Listener</code> method.
323+ * <p>
324+ * You can specify the <code>listenerType</code> argument
325+ * with a class literal, such as <code><em>Foo</em>Listener.class</code>.
326+ * For example, you can query a <code>Timer</code>
327+ * instance <code>t</code>
328+ * for its action listeners
329+ * with the following code:
330+ *
331+ * <pre>ActionListener[] als = (ActionListener[])(t.getListeners(ActionListener.class));</pre>
332+ *
333+ * If no such listeners exist,
334+ * this method returns an empty array.
335+ *
336+ * @param listenerType the type of listeners requested;
337+ * this parameter should specify an interface
338+ * that descends from <code>java.util.EventListener</code>
339+ * @return an array of all objects registered as
340+ * <code><em>Foo</em>Listener</code>s
341+ * on this timer,
342+ * or an empty array if no such
343+ * listeners have been added
344+ * @exception ClassCastException if <code>listenerType</code> doesn't
345+ * specify a class or interface that implements
346+ * <code>java.util.EventListener</code>
347+ *
348+ * @see #getActionListeners
349+ * @see #addActionListener
350+ * @see #removeActionListener
351+ *
352+ * @since 1.3
353+ */
354+ public <T extends EventListener> T[] getListeners(Class<T> listenerType) {
355+ return listenerList.getListeners(listenerType);
356+ }
357+
358+ /**
359+ * Returns the timer queue.
360+ */
361+ private TimerQueue timerQueue() {
362+ return TimerQueue.sharedInstance();
363+ }
364+
365+
366+ /**
367+ * Enables or disables the timer log. When enabled, a message
368+ * is posted to <code>System.out</code> whenever the timer goes off.
369+ *
370+ * @param flag <code>true</code> to enable logging
371+ * @see #getLogTimers
372+ */
373+ public static void setLogTimers(boolean flag) {
374+ logTimers = flag;
375+ }
376+
377+
378+ /**
379+ * Returns <code>true</code> if logging is enabled.
380+ *
381+ * @return <code>true</code> if logging is enabled; otherwise, false
382+ * @see #setLogTimers
383+ */
384+ public static boolean getLogTimers() {
385+ return logTimers;
386+ }
387+
388+
389+ /**
390+ * Sets the <code>Timer</code>'s between-event delay, the number of milliseconds
391+ * between successive action events. This does not affect the initial delay
392+ * property, which can be set by the {@code setInitialDelay} method.
393+ *
394+ * @param delay the delay in milliseconds
395+ * @see #setInitialDelay
396+ */
397+ public void setDelay(int delay) {
398+ if (delay < 0) {
399+ throw new IllegalArgumentException("Invalid delay: " + delay);
400+ }
401+ else {
402+ this.delay = delay;
403+ }
404+ }
405+
406+
407+ /**
408+ * Returns the delay, in milliseconds,
409+ * between firings of action events.
410+ *
411+ * @see #setDelay
412+ * @see #getInitialDelay
413+ */
414+ public int getDelay() {
415+ return delay;
416+ }
417+
418+
419+ /**
420+ * Sets the <code>Timer</code>'s initial delay, the time
421+ * in milliseconds to wait after the timer is started
422+ * before firing the first event. Upon construction, this
423+ * is set to be the same as the between-event delay,
424+ * but then its value is independent and remains unaffected
425+ * by changes to the between-event delay.
426+ *
427+ * @param initialDelay the initial delay, in milliseconds
428+ * @see #setDelay
429+ */
430+ public void setInitialDelay(int initialDelay) {
431+ if (initialDelay < 0) {
432+ throw new IllegalArgumentException("Invalid initial delay: " +
433+ initialDelay);
434+ }
435+ else {
436+ this.initialDelay = initialDelay;
437+ }
438+ }
439+
440+
441+ /**
442+ * Returns the <code>Timer</code>'s initial delay.
443+ *
444+ * @see #setInitialDelay
445+ * @see #setDelay
446+ */
447+ public int getInitialDelay() {
448+ return initialDelay;
449+ }
450+
451+
452+ /**
453+ * If <code>flag</code> is <code>false</code>,
454+ * instructs the <code>Timer</code> to send only one
455+ * action event to its listeners.
456+ *
457+ * @param flag specify <code>false</code> to make the timer
458+ * stop after sending its first action event
459+ */
460+ public void setRepeats(boolean flag) {
461+ repeats = flag;
462+ }
463+
464+
465+ /**
466+ * Returns <code>true</code> (the default)
467+ * if the <code>Timer</code> will send
468+ * an action event
469+ * to its listeners multiple times.
470+ *
471+ * @see #setRepeats
472+ */
473+ public boolean isRepeats() {
474+ return repeats;
475+ }
476+
477+
478+ /**
479+ * Sets whether the <code>Timer</code> coalesces multiple pending
480+ * <code>ActionEvent</code> firings.
481+ * A busy application may not be able
482+ * to keep up with a <code>Timer</code>'s event generation,
483+ * causing multiple
484+ * action events to be queued. When processed,
485+ * the application sends these events one after the other, causing the
486+ * <code>Timer</code>'s listeners to receive a sequence of
487+ * events with no delay between them. Coalescing avoids this situation
488+ * by reducing multiple pending events to a single event.
489+ * <code>Timer</code>s
490+ * coalesce events by default.
491+ *
492+ * @param flag specify <code>false</code> to turn off coalescing
493+ */
494+ public void setCoalesce(boolean flag) {
495+ boolean old = coalesce;
496+ coalesce = flag;
497+ if (!old && coalesce) {
498+ // We must do this as otherwise if the Timer once notified
499+ // in !coalese mode notify will be stuck to true and never
500+ // become false.
501+ cancelEvent();
502+ }
503+ }
504+
505+
506+ /**
507+ * Returns <code>true</code> if the <code>Timer</code> coalesces
508+ * multiple pending action events.
509+ *
510+ * @see #setCoalesce
511+ */
512+ public boolean isCoalesce() {
513+ return coalesce;
514+ }
515+
516+
517+ /**
518+ * Sets the string that will be delivered as the action command
519+ * in <code>ActionEvent</code>s fired by this timer.
520+ * <code>null</code> is an acceptable value.
521+ *
522+ * @param command the action command
523+ * @since 1.6
524+ */
525+ public void setActionCommand(String command) {
526+ this.actionCommand = command;
527+ }
528+
529+
530+ /**
531+ * Returns the string that will be delivered as the action command
532+ * in <code>ActionEvent</code>s fired by this timer. May be
533+ * <code>null</code>, which is also the default.
534+ *
535+ * @return the action command used in firing events
536+ * @since 1.6
537+ */
538+ public String getActionCommand() {
539+ return actionCommand;
540+ }
541+
542+
543+ /**
544+ * Starts the <code>Timer</code>,
545+ * causing it to start sending action events
546+ * to its listeners.
547+ *
548+ * @see #stop
549+ */
550+ public void start() {
551+ timerQueue().addTimer(this, getInitialDelay());
552+ }
553+
554+
555+ /**
556+ * Returns <code>true</code> if the <code>Timer</code> is running.
557+ *
558+ * @see #start
559+ */
560+ public boolean isRunning() {
561+ return timerQueue().containsTimer(this);
562+ }
563+
564+
565+ /**
566+ * Stops the <code>Timer</code>,
567+ * causing it to stop sending action events
568+ * to its listeners.
569+ *
570+ * @see #start
571+ */
572+ public void stop() {
573+ getLock().lock();
574+ try {
575+ cancelEvent();
576+ timerQueue().removeTimer(this);
577+ } finally {
578+ getLock().unlock();
579+ }
580+ }
581+
582+
583+ /**
584+ * Restarts the <code>Timer</code>,
585+ * canceling any pending firings and causing
586+ * it to fire with its initial delay.
587+ */
588+ public void restart() {
589+ getLock().lock();
590+ try {
591+ stop();
592+ start();
593+ } finally {
594+ getLock().unlock();
595+ }
596+ }
597+
598+
599+ /**
600+ * Resets the internal state to indicate this Timer shouldn't notify
601+ * any of its listeners. This does not stop a repeatable Timer from
602+ * firing again, use <code>stop</code> for that.
603+ */
604+ void cancelEvent() {
605+ notify.set(false);
606+ }
607+
608+
609+ void post() {
610+ if (notify.compareAndSet(false, true) || !coalesce) {
611+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
612+ public Void run() {
613+ SwingUtilities.invokeLater(doPostEvent);
614+ return null;
615+ }
616+ }, getAccessControlContext());
617+ }
618+ }
619+
620+ Lock getLock() {
621+ return lock;
622+ }
623+
624+ private void readObject(ObjectInputStream in)
625+ throws ClassNotFoundException, IOException
626+ {
627+ this.acc = AccessController.getContext();
628+ in.defaultReadObject();
629+ }
630+
631+ /*
632+ * We have to use readResolve because we can not initialize final
633+ * fields for deserialized object otherwise
634+ */
635+ private Object readResolve() {
636+ Timer timer = new Timer(getDelay(), null);
637+ timer.listenerList = listenerList;
638+ timer.initialDelay = initialDelay;
639+ timer.delay = delay;
640+ timer.repeats = repeats;
641+ timer.coalesce = coalesce;
642+ timer.actionCommand = actionCommand;
643+ return timer;
644+ }
645+}