OSDN Git Service

c339c8b0544a3733f2c26bde9e2919b872b02351
[pf3gnuchains/gcc-fork.git] / libjava / javax / swing / Timer.java
1 /* Timer.java --
2    Copyright (C) 2002, 2004, 2005  Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38
39 package javax.swing;
40
41 import java.awt.event.ActionEvent;
42 import java.awt.event.ActionListener;
43 import java.io.Serializable;
44 import java.util.EventListener;
45
46 import javax.swing.event.EventListenerList;
47
48 /**
49  * Fires one or more action events after the specified delay.
50  * @author Ronald Veldema
51  * @author Audrius Meskauskas (audriusa@Bionformatics.org) - bug fixes
52  * and documentation comments
53  */
54 public class Timer
55   implements Serializable
56 {
57   /** DOCUMENT ME! */
58   private static final long serialVersionUID = -1116180831621385484L;
59
60   /** DOCUMENT ME! */
61   protected EventListenerList listenerList = new EventListenerList();
62
63   // This object manages a "queue" of virtual actionEvents, maintained as a
64   // simple long counter. When the timer expires, a new event is queued,
65   // and a dispatcher object is pushed into the system event queue. When
66   // the system thread runs the dispatcher, it will fire as many
67   // ActionEvents as have been queued, unless the timer is set to
68   // coalescing mode, in which case it will fire only one ActionEvent.
69
70   /** DOCUMENT ME! */
71   private long queue;
72
73   /** DOCUMENT ME! */
74   private Object queueLock = new Object();
75
76   /** DOCUMENT ME! */
77   private Waker waker;
78
79   private Runnable drainer = new Runnable() 
80     {
81       public void run()
82       {
83         drainEvents();
84       }
85     };
86
87   /**
88    * DOCUMENT ME!
89    * Package-private to avoid an accessor method.
90    */
91   private void queueEvent()
92   {
93     synchronized (queueLock)
94       {
95         queue++;
96         if (queue == 1)
97           SwingUtilities.invokeLater(drainer);
98       }
99   }
100
101   /**
102    * DOCUMENT ME!
103    * This is package-private to avoid an accessor method.
104    */
105   void drainEvents()
106   {
107     synchronized (queueLock)
108       {
109         if (isCoalesce())
110           {
111             if (queue > 0)
112               fireActionPerformed();
113           }
114         else
115           {
116             while (queue > 0)
117               {
118                 fireActionPerformed();
119                 queue--;
120               }
121           }
122         queue = 0;
123       }
124   }
125
126   static boolean logTimers;
127
128   /**
129    * <code>true</code> if the timer coalesces events.
130    */
131   boolean coalesce = true;
132
133   /**
134    * <code>true</code> if the timer is firing repetetive events.
135    */
136   boolean repeats = true;
137
138   /**
139    * <code>true</code> if the timer is currently active, firing events
140    * as scheduled.
141    */
142   boolean running;
143
144   /** DOCUMENT ME! */
145   int ticks;
146
147   /**
148    * The delay between subsequent repetetive events.
149    */
150   int delay;
151
152   /**
153    * The initial delay before the first event.
154    */
155   int initialDelay;
156
157   /**
158    * DOCUMENT ME!
159    */
160   private class Waker extends Thread
161   {
162     /**
163      * DOCUMENT ME!
164      */
165     public void run()
166     {
167       running = true;
168       try
169         {
170           sleep(initialDelay);
171
172           while (running)
173             {
174               try
175                 {
176                   sleep(delay);
177                 }
178               catch (InterruptedException e)
179                 {
180                   return;
181                 }
182               queueEvent();
183
184               if (logTimers)
185                 System.out.println("javax.swing.Timer -> clocktick");
186
187               if (! repeats)
188                 break;
189             }
190           running = false;
191         }
192       catch (Exception e)
193         {
194 //        System.out.println("swing.Timer::" + e);
195         }
196     }
197   }
198
199   /**
200    * Creates a new Timer object.
201    *
202    * @param d the default value for both initial and between event delay, in
203    * milliseconds.
204    * @param listener the first action listener, can be <code>null</code>.
205    */
206   public Timer(int d, ActionListener listener)
207   {
208     delay = d;
209
210     if (listener != null)
211       addActionListener(listener);
212   }
213
214   /**
215    * DOCUMENT ME!
216    *
217    * @param c DOCUMENT ME!
218    */
219   public void setCoalesce(boolean c)
220   {
221     coalesce = c;
222   }
223
224   /**
225    * DOCUMENT ME!
226    *
227    * @return DOCUMENT ME!
228    */
229   public boolean isCoalesce()
230   {
231     return coalesce;
232   }
233
234   /**
235    * DOCUMENT ME!
236    *
237    * @param listener DOCUMENT ME!
238    */
239   public void addActionListener(ActionListener listener)
240   {
241     listenerList.add(ActionListener.class, listener);
242   }
243
244   /**
245    * DOCUMENT ME!
246    *
247    * @param listener DOCUMENT ME!
248    */
249   public void removeActionListener(ActionListener listener)
250   {
251     listenerList.remove(ActionListener.class, listener);
252   }
253
254   /**
255    * Get the event listeners of the given type that are listening for the
256    * events, fired by this timer.
257    *
258    * @param listenerType the listener type (for example, ActionListener.class)
259    *
260    * @return the array of event listeners that are listening for the events,
261    * fired by this timer
262    * @since 1.3
263    */
264   public EventListener[] getListeners(Class listenerType)
265   {
266     return listenerList.getListeners(listenerType);
267   }
268
269   /**
270    * DOCUMENT ME!
271    *
272    * @return DOCUMENT ME!
273    *
274    * @since 1.4
275    */
276   public ActionListener[] getActionListeners()
277   {
278     return (ActionListener[]) listenerList.getListeners(ActionListener.class);
279   }
280
281   /**
282    * DOCUMENT ME!
283    *
284    * @param event DOCUMENT ME!
285    */
286   protected void fireActionPerformed(ActionEvent event)
287   {
288     ActionListener[] listeners = getActionListeners();
289
290     for (int i = 0; i < listeners.length; i++)
291       listeners[i].actionPerformed(event);
292   }
293
294   /**
295    * DOCUMENT ME!
296    */
297   void fireActionPerformed()
298   {
299     fireActionPerformed(new ActionEvent(this, ticks++, "Timer"));
300   }
301
302   /**
303    * Set the timer logging state. If it is set to <code>true</code>, the
304    * timer prints a message to {@link System#out} when firing each
305    * action event.
306    *
307    * @param lt <code>true</code> if logging is enabled, <code>false</code>
308    * (default value) otherwise
309    */
310   public static void setLogTimers(boolean lt)
311   {
312     logTimers = lt;
313   }
314
315   /**
316    * Return the logging state.
317    *
318    * @return <code>true</code> if the timer is printing a message to
319    * {@link System#out}
320    * when firing each action event
321    */
322   public static boolean getLogTimers()
323   {
324     return logTimers;
325   }
326
327   /**
328    * Set the delay between firing the subsequent events.
329    * This parameter does not change the value of the initial delay before
330    * firing the first event.
331    *
332    * @param d The time gap between the subsequent events, in milliseconds
333    */
334   public void setDelay(int d)
335   {
336     delay = d;
337   }
338
339   /**
340    * Get the delay between firing the subsequent events.
341    *
342    * @return The delay between subsequent events, in milliseconds
343    */
344   public int getDelay()
345   {
346     return delay;
347   }
348
349   /**
350    * Set the intial delay before firing the first event since calling
351    * the {@link #start()} method. If the initial delay has not been
352    * set, it is assumed having the same value as the delay between the
353    * subsequent events.
354    *
355    * @param i the initial delay, in milliseconds
356    */
357   public void setInitialDelay(int i)
358   {
359     initialDelay = i;
360   }
361
362   /**
363    * Get the intial delay before firing the first event since calling
364    * the {@link #start()} method. If the initial delay has not been
365    * set, returns the same value as {@link #getDelay()}.
366    *
367    * @return the initial delay before firing the first action event.
368    */
369   public int getInitialDelay()
370   {
371     return initialDelay;
372   }
373
374   /**
375    * Enable firing the repetetive events.
376    *
377    * @param r <code>true</code> (default value) to fire repetetive events.
378    * <code>false</code> to fire
379    * only one event after the initial delay
380    */
381   public void setRepeats(boolean r)
382   {
383     repeats = r;
384   }
385
386   /**
387    * Check is this timer fires repetetive events.
388    *
389    * @return <code>true</code> if the timer fires repetetive events,
390    * <code>false</code> if it fires
391    * only one event after the initial delay
392    */
393   public boolean isRepeats()
394   {
395     return repeats;
396   }
397
398   /**
399    * Get the timer state.
400    *
401    * @return <code>true</code> if the timer has been started and is firing
402    * the action events as scheduled. <code>false</code>
403    * if the timer is inactive.
404    */
405   public boolean isRunning()
406   {
407     return running;
408   }
409
410   /**
411    * DOCUMENT ME!
412    */
413   public void start()
414   {
415     if (isRunning())
416       return;
417     waker = new Waker();
418     waker.start();
419   }
420
421   /**
422    * DOCUMENT ME!
423    */
424   public void restart()
425   {
426     stop();
427     start();
428   }
429
430   /**
431    * DOCUMENT ME!
432    */
433   public void stop()
434   {
435     running = false;
436     if (waker != null)
437       waker.interrupt();
438     synchronized (queueLock)
439       {
440         queue = 0;
441       }
442   }
443 }