X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=libjava%2Fjavax%2Fswing%2FTimer.java;h=eac5832a381be05ba24661b9485811392d48fcf0;hp=fd88351f417eb4607823a8df0673bc139a426706;hb=f8e976477ab53b06a7cb0edbe59fb6ac7957ee65;hpb=848ad1d5b17a69b163abc0986cd33f6c64b921f1 diff --git a/libjava/javax/swing/Timer.java b/libjava/javax/swing/Timer.java index fd88351f417..eac5832a381 100644 --- a/libjava/javax/swing/Timer.java +++ b/libjava/javax/swing/Timer.java @@ -1,5 +1,5 @@ -/* Timer.java -- - Copyright (C) 2002, 2004 Free Software Foundation, Inc. +/* Timer.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -45,134 +45,436 @@ import java.util.EventListener; import javax.swing.event.EventListenerList; -public class Timer implements Serializable +/** + * Fires one or more action events after the specified delay. + * @author Ronald Veldema + * @author Audrius Meskauskas (audriusa@Bionformatics.org) - bug fixes + * and documentation comments + */ +public class Timer + implements Serializable { - protected EventListenerList listenerList = new EventListenerList(); - - int ticks; - static boolean verbose; - boolean running; - boolean repeat_ticks = true; - long interval, init_delay; - - class Waker extends Thread + /** + * The timer thread + */ + private class Waker + extends Thread { + /** + * Fires events, pausing for required intervals. + */ public void run() { running = true; - try { - sleep(init_delay); - - while (running) - { - sleep(interval); - - if (verbose) - { - System.out.println("javax.swing.Timer -> clocktick"); - } - - ticks++; - fireActionPerformed(); - - if (! repeat_ticks) - break; - } - running = false; - } catch (Exception e) { - System.out.println("swing.Timer::" + e); - } + try + { + sleep(initialDelay); + + while (running) + { + try + { + sleep(delay); + } + catch (InterruptedException e) + { + return; + } + queueEvent(); + + if (logTimers) + System.out.println("javax.swing.Timer -> clocktick"); + + if ( ! repeats) + break; + } + running = false; + } + catch (Exception e) + { + } } } - public void addActionListener(ActionListener listener) - { - listenerList.add (ActionListener.class, listener); - } - - public void removeActionListener(ActionListener listener) + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = -1116180831621385484L; + + /** + * The encloding class, used with {@link SwingUtilities#invokeLater} + * to invoke the {@link #drainEvents()}. + */ + private Runnable drainer = new Runnable() + { + public void run() + { + drainEvents(); + } + }; + + /** + * If true, the timer prints a message to + * {@link System#out} when firing each event. + */ + static boolean logTimers; + + /** + * A field to store all listeners who are listening to this timer. + */ + protected EventListenerList listenerList = new EventListenerList(); + + /** + * true if the timer coalesces events. + */ + boolean coalesce = true; + + /** + * true if the timer is firing repetetive events. + */ + boolean repeats = true; + + /** + * true if the timer is currently active, firing events + * as scheduled. + */ + boolean running; + + /** + * The delay between subsequent repetetive events. + */ + int delay; + + /** + * The initial delay before the first event. + */ + int initialDelay; + + /** + * The number of events that have been already fired by this timer. + * This is used as a numeric identifier for the next event that would + * be fired. + */ + int ticks; + + /** + * Stores the thread that posts events to the queue at required time + * intervals. + */ + private Waker waker; + + /** + * This object manages a "queue" of virtual actionEvents, maintained as a + * simple long counter. When the timer expires, a new event is queued, + * and a dispatcher object is pushed into the system event queue. When + * the system thread runs the dispatcher, it will fire as many + * ActionEvents as have been queued, unless the timer is set to + * coalescing mode, in which case it will fire only one ActionEvent. + */ + private long queue; + + /** + * synchronized(queueLock) replaces + * synchronized(queue) that is not supported by this language. + */ + private Object queueLock = new Object(); + + /** + * Creates a new Timer object. + * + * @param d the default value for both initial and between event delay, in + * milliseconds. + * @param listener the first action listener, can be null. + */ + public Timer(int d, ActionListener listener) { - listenerList.remove (ActionListener.class, listener); + delay = d; + + if (listener != null) + addActionListener(listener); } /** - * @since 1.3 + * Get the array of action listeners. + * + * @return the array of action listeners that are listening for the events, + * fired by this timer + * + * @since 1.4 */ - public EventListener[] getListeners (Class listenerType) + public ActionListener[] getActionListeners() { - return listenerList.getListeners (listenerType); + return (ActionListener[]) listenerList.getListeners(ActionListener.class); } - + /** - * @since 1.4 + * Sets whether the Timer coalesces multiple pending event firings. + * If the coalescing is enabled, the multiple events that have not been + * fired on time are replaced by the single event. The events may not + * be fired on time if the application is busy. + * + * @param c true (default) to enable the event coalescing, + * false otherwise */ - public ActionListener[] getActionListeners () + public void setCoalesce(boolean c) { - return (ActionListener[]) listenerList.getListeners (ActionListener.class); + coalesce = c; } - protected void fireActionPerformed (ActionEvent event) + /** + * Checks if the Timer coalesces multiple pending event firings. + * If the coalescing is enabled, the multiple events that have not been + * fired on time are replaced by the single event. The events may not + * be fired on time if the application is busy. + * + * @return true if the coalescing is enabled, + * false otherwise + */ + public boolean isCoalesce() { - ActionListener[] listeners = getActionListeners(); - - for (int i = 0; i < listeners.length; i++) - { - listeners [i].actionPerformed (event); - } + return coalesce; } - void fireActionPerformed () + /** + * Get the event listeners of the given type that are listening for the + * events, fired by this timer. + * + * @param listenerType the listener type (for example, ActionListener.class) + * + * @return the array of event listeners that are listening for the events, + * fired by this timer + * @since 1.3 + */ + public EventListener[] getListeners(Class listenerType) { - fireActionPerformed (new ActionEvent (this, ticks, "Timer")); + return listenerList.getListeners(listenerType); } - public static void setLogTimers(boolean flag) + /** + * Set the timer logging state. If it is set to true, the + * timer prints a message to {@link System#out} when firing each + * action event. + * + * @param lt true if logging is enabled, false + * (default value) otherwise + */ + public static void setLogTimers(boolean lt) { - verbose = flag; + logTimers = lt; } + /** + * Return the logging state. + * + * @return true if the timer is printing a message to + * {@link System#out} + * when firing each action event + */ public static boolean getLogTimers() { - return verbose; + return logTimers; } - - public void setDelay(int delay) + + /** + * Set the delay between firing the subsequent events. + * This parameter does not change the value of the initial delay before + * firing the first event. + * + * @param d The time gap between the subsequent events, in milliseconds + */ + public void setDelay(int d) { - interval = delay; + delay = d; } + /** + * Get the delay between firing the subsequent events. + * + * @return The delay between subsequent events, in milliseconds + */ public int getDelay() { - return (int)interval; + return delay; } - public void setInitialDelay(int initialDelay) + /** + * Set the intial delay before firing the first event since calling + * the {@link #start()} method. If the initial delay has not been + * set, it is assumed having the same value as the delay between the + * subsequent events. + * + * @param i the initial delay, in milliseconds + */ + public void setInitialDelay(int i) + { + initialDelay = i; + } + + /** + * Get the intial delay before firing the first event since calling + * the {@link #start()} method. If the initial delay has not been + * set, returns the same value as {@link #getDelay()}. + * + * @return the initial delay before firing the first action event. + */ + public int getInitialDelay() + { + return initialDelay; + } + + /** + * Enable firing the repetetive events. + * + * @param r true (default value) to fire repetetive events. + * false to fire + * only one event after the initial delay + */ + public void setRepeats(boolean r) { - init_delay = initialDelay; + repeats = r; } - public void setRepeats(boolean flag) + /** + * Check is this timer fires repetetive events. + * + * @return true if the timer fires repetetive events, + * false if it fires + * only one event after the initial delay + */ + public boolean isRepeats() { - repeat_ticks = flag; + return repeats; } + /** + * Get the timer state. + * + * @return true if the timer has been started and is firing + * the action events as scheduled. false + * if the timer is inactive. + */ public boolean isRunning() { return running; } + /** + * Add the action listener + * + * @param listener the action listener to add + */ + public void addActionListener(ActionListener listener) + { + listenerList.add(ActionListener.class, listener); + } + + /** + * Remove the action listener. + * + * @param listener the action listener to remove + */ + public void removeActionListener(ActionListener listener) + { + listenerList.remove(ActionListener.class, listener); + } + + /** + * Cancel all pending tasks and fire the first event after the initial + * delay. + */ + public void restart() + { + stop(); + start(); + } + + /** + * Start firing the action events. + */ public void start() { if (isRunning()) - { - System.err.println("attempt to start a running timer"); - return; - } - new Waker().start(); + return; + waker = new Waker(); + waker.start(); } + /** + * Stop firing the action events. + */ public void stop() { running = false; + if (waker != null) + waker.interrupt(); + synchronized (queueLock) + { + queue = 0; + } + } + + /** + * Fire the given action event to the action listeners. + * + * @param event the event to fire + */ + protected void fireActionPerformed(ActionEvent event) + { + ActionListener[] listeners = getActionListeners(); + + for (int i = 0; i < listeners.length; i++) + listeners [ i ].actionPerformed(event); + } + + /** + * Fire the action event, named "Timer" and having the numeric + * identifier, equal to the numer of events that have been + * already fired before. + */ + void fireActionPerformed() + { + fireActionPerformed(new ActionEvent(this, ticks++, "Timer")); + } + + /** + * Fire the queued action events. + * In the coalescing mode, a single event is fired as a replacement + * for all queued events. In non coalescing mode, a series of + * all queued events is fired. + * This is package-private to avoid an accessor method. + */ + void drainEvents() + { + synchronized (queueLock) + { + if (isCoalesce()) + { + if (queue > 0) + fireActionPerformed(); + } + else + { + while (queue > 0) + { + fireActionPerformed(); + queue--; + } + } + queue = 0; + } + } + + /** + * Post a scheduled event to the event queue. + * Package-private to avoid an accessor method. + */ + private void queueEvent() + { + synchronized (queueLock) + { + queue++; + if (queue == 1) + SwingUtilities.invokeLater(drainer); + } } }