United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-4434193 ActionEvents (and other events) need timestamps
JDK-4434193 : ActionEvents (and other events) need timestamps

Details
Type:
Bug
Submit Date:
2001-04-05
Status:
Resolved
Updated Date:
2001-07-31
Project Name:
JDK
Resolved Date:
2001-07-31
Component:
client-libs
OS:
windows_nt,generic
Sub-Component:
java.awt
CPU:
x86,generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.3.0,1.4.0
Fixed Versions:
1.4.0 (beta2)

Related Reports
Duplicate:
Relates:
Relates:

Sub Tasks

Description
if in EventDispatchThread we are processing a ActionEvent
the EventQueue.getDispatchingEventTime returns current system time.
it's possible that this time value is greater than the timestamp of
KeyEvents posted later than the ActionEvent being dispatched.
so if we use this time value to call 
DefaultKeyboardFocusManager.enqueueKeyEvents
we might not get the desired behavior(hold any keyEvent which is
posted after the current event)

tao.ma@Eng 2001-04-04

                                    

Comments
SUGGESTED FIX

according to David Mendenhall, ActionEvent should have a getWhen method,
and DefaultKeyboardFocusManager should be updated appropriatly.

tao.ma@Eng 2001-04-04
                                     
2001-04-04
EVALUATION

    public InputMethodEvent(Component source, int id,
                            AttributedCharacterIterator text,
                            int committedCharacterCount, TextHitInfo caret,
                            TextHitInfo visiblePosition);

    /**
     * Constructs an <code>InputMethodEvent</code> with the specified source
     * component, type, caret, and visiblePosition. The text is set to
     * <code>null</code>, <code>committedCharacterCount</code> to 0.
     * <p>
     * The offsets of <code>caret</code> and <code>visiblePosition</code> are
     * relative to the current composed text; that is, the composed text within
     * the <code>text</code> of the preceding
     * <code>INPUT_METHOD_TEXT_CHANGED</code> event if the event being
     * constructed as a <code>CARET_POSITION_CHANGED</code> event. For an
     * <code>INPUT_METHOD_TEXT_CHANGED</code> event without text,
     * <code>caret</code> and <code>visiblePosition</code> must be
!    * <code>null</code>. The time stamp for this event is initialized by
!    * invoking {@link java.awt.EventQueue#getMostRecentEventTime()}.
     *
     * @param source the object where the event originated
     * @param id the event type
     * @param caret the caret (a.k.a. insertion point);
     *      <code>null</code> if there's no caret within current
     *      composed text
     * @param visiblePosition the position that's most important
     *      to be visible; <code>null</code> if there's no
     *      recommendation for a visible position within current
     *      composed text
     * @exception IllegalArgumentException if <code>id</code> is not
     *      in the range
     *      <code>INPUT_METHOD_FIRST</code>..<code>INPUT_METHOD_LAST</code>
     */
    public InputMethodEvent(Component source, int id, TextHitInfo caret,
                            TextHitInfo visiblePosition);


Add the following methods to java.awt.EventQueue:

    /**
     * Returns the timestamp of the most recent event that had a timestamp, and
     * that was dispatched from the <code>EventQueue</code> associated with the
     * calling thread. If an event with a timestamp is currently being
     * dispatched, its timestamp will be returned. In the current version of
     * the Java platform SDK, only <code>InputEvent</code>s,
     * <code>ActionEvent</code>s, <code>InvocationEvent</code>s, and
     * <code>InputMethodEvent</code>s have timestamps; however, future versions
     * of the SDK may add timestamps to additional event types. Note that this
     * method should only be invoked from an application's event dispatching
     * thread. If this method is invoked from another thread, the current
     * system time (as reported by <code>System.currentTimeMillis()</code>)
     * will be returned instead.
     *
     * @return the timestamp of the last <code>InputEvent</code>,
     *         <code>ActionEvent</code>, <code>InvocationEvent</code>, or
     *         <code>InputMethodEvent</code> to be dispatched, or
     *         <code>System.currentTimeMillis()</code> if this method is
     *         invoked on a thread other than an event dispatching thread
     * @see java.awt.event.InputEvent#getWhen
     * @see java.awt.event.ActionEvent#getWhen
     * @see java.awt.event.InvocationEvent#getWhen
     * @see java.awt.event.InputMethodEvent#getWhen
     *
     * @since 1.4
     */
    public static long getMostRecentEventTime();

    /**
     * Returns the the event currently being dispatched by the
     * <code>EventQueue</code> associated with the calling thread. This is
     * useful if a method needs access to the event, but was not designed to
     * receive a reference to it as an argument. Note that this method should
     * only be invoked from an application's event dispatching thread. If this
     * method is invoked from another thread, null will be returned.
     *
     * @return the event currently being dispatched, or null if this method is
     *         invoked on a thread other than an event dispatching thread
     * @since 1.4
     */
    public static AWTEvent getCurrentEvent();


API reviewed and approved by:

awt-core@eng swing-eng@eng java-i18n@eng


Implementation:
   - Engineer who made (or will make) the changes: David Mendenhall, Naoto Sato
   - Date at which changes will be complete: Immediately
   - Number of lines of new or modified code:
        + Java: TBD
        + Native: TBD
   - Code reviewed (or will be reviewed) by: TBD


Risk assessment:

Low. This API change should be purely an addition of code, and should not
affect any existing code. Any bugs introduced would almost certainly be
confined to the new feature itself.


SQE impact:

TBD

JCK impact:

TBD


Doc impact:

javadoc changes only.


Localization impact:

None.


Internationalization impact:

None.


Security impact:

None.


Legal impact:

None.


For feature changes, Product Marketing approval:

N/A
david.mendenhall@east 2001-06-20
                                     
2001-06-20
EVALUATION

Needed to correctly fix regression from kestrel.
david.mendenhall@east 2001-04-05

Release: merlin-beta-refresh

Problem: (BugIDs 4434193 and 4026963)
  ActionEvents (and other events) need timestamps
  getModifiers() in class ActionEvent always returns 0 (JDC Top 25 Bug)

The new focus architecture includes a type-ahead mechanism that
ensures that subsequent KeyEvents that follow a KeyEvent that
initiates a focus transfer are not delivered until the transfer is
completed. The design for this feature is based on the UTC timestamps
of the various events. Events with timestamps later than that of the
initiating event are enqueued pending resolution of the transfer;
events with earlier timestamps are not.

To implement this feature, the focus code keeps track of the timestamp
of the event currently being handled. If a focus change is initiated
during this handling, the timestamp is available for use. However, if
the current event does not have a timestamp, then the current system
time is used. This time is usually too far ahead of the time that the
event actually occurred to be of any real use. As a result, the
type-ahead mechanism fails, and KeyEvents are delivered before the
focus transfer is completed.

The most common case where we encounter this problem is with
ActionEvents. ActionEvents are high-level, semantic events generated
in response to underlying InputEvents. While the InputEvents have
timestamps associated with them, the ActionEvents do not. The
ActionEvent API must be expanded to accommodate a timestamp, and the
implementation must be updated so that an ActionEvent's timestamp is
equal to that of its underlying InputEvent.

Another common case that exhibits the same problem is with
InvocationEvents synthesized from calls to
EventQueue.invokeLater(Runnable), EventQueue.invokeAndWait(Runnable),
SwingUtilities.invokeLater(Runnable), and
SwingUtilities.invokeAndWait(Runnable). Therefore, the InvocationEvent
API must also be expanded to accommodate a timestamp.

A final important case is with InputMethodEvents. These are roughly
equivalent to InputEvents, as they are generated in direct response to
a user's actions. However, unlike InputEvents, InputMethodEvents
currently do not have timestamps. The InputMethodEvent API must be
expanded to accommodate a timestamp. For InputMethodEvents that are
generated by a native, host input method, the timestamp must be equal
to the timestamp of the underlying native event. For InputMethodEvents
that are generated by a Java input method, the timestamp must be equal
to the underlying InputEvent.

In addition, we must address the issue that Swing often synthesizes
ActionEvents from methods that do not have access to the underlying
InputEvent. While we could add new versions of these methods that take
an InputEvent as an argument, this would require developers to update
existing applications to invoke the new versions of these
methods. Without such an update, Swing would be forced to synthesize
ActionEvents with nonsensical timestamps.

An alternate approach is for the AWT to store the timestamp of the
last InputEvent, ActionEvent, InvocationEvent, or InputMethodEvent
that was dispatched. Because Swing is an event-driven architecture,
ActionEvents are only synthesized as part of the processing of another
event. Typically, the event currently being processed at such times
has a timestamp, so the stored value is exactly correct. In some edge
cases, the event currently being processed is of some other type;
however, because all events are fundamentally generated as a result of
an event that has a timestamp, the timestamp of the last such event
is appropriate. This value is also appropriate as the timestamp for
all InvocationEvents, and for ActionEvents and InputMethodEvents that
are instantiated without an explicit timestamp (using the existing
constructors, rather than the new ones specified in this document).

If this same approach is applied to the current event in general, we
can also resolve a long-standing JDC Top 25 bug. BugID 4026963
documents a bug in the AWT and Swing wherein almost all ActionEvents
have a 'modifiers' field of zero, even if the underlying event had a
non-zero 'modifiers' field. While many of the problem cases can be
corrected without an API change, several of the Swing cases cannot be
fixed because, as with the timestamps, the code synthesizing the
ActionEvent does not have access to the underlying event.


Requesters:

AWT Core (David Mendenhall)
I18N (Naoto Sato)
CTE (Tao Ma)


Proposed API change:

Add the following methods to java.awt.event.ActionEvent:

    /**
     * Constructs an <code>ActionEvent</code> object with the specified
     * modifier keys and timestamp.
     * <p>
     * Note that passing in an invalid <code>id</code> results in unspecified
     * behavior.
     *
     * @param source    the object that originated the event
     * @param id        an integer that identifies the event
     * @param command   a string that may specify a command (possibly one 
     *                  of several) associated with the event
     * @param when      the time the event occurred
     * @param modifiers the modifier keys held down during this action
     *
     * @since 1.4
     */
    public ActionEvent(Object source, int id, String command, long when,
                       int modifiers);

    /**
     * Returns the timestamp of when this event occurred. Because an
     * ActionEvent is a high-level, semantic event, the timestamp is typically
     * the same as an underlying InputEvent.
     *
     * @return this event's timestamp
     * @since 1.4
     */
    public long getWhen();

    /**
     * Initializes the <code>when</code> field if it is not present in the
     * object input stream. In that case, the field will be initialized by
     * invoking {@link java.awt.EventQueue#getMostRecentEventTime()}.
     */
    private void readObject(ObjectInputStream s) throws
	ClassNotFoundException, IOException;


Modify the following existing methods of java.awt.event.ActionEvent as
follows:

    /**
!    * Constructs an <code>ActionEvent</code> object. The timestamp for this
!    * event is initialized by invoking
!    * {@link java.awt.EventQueue#getMostRecentEventTime()}.
     * <p>
     * Note that passing in an invalid <code>id</code> results in unspecified
     * behavior.
     *
     * @param source  the object that originated the event
     * @param id      an integer that identifies the event
     * @param command a string that may specify a command (possibly one 
     *                of several) associated with the event
     */
    public ActionEvent(Object source, int id, String command);

    /**
!    * Constructs an <code>ActionEvent</code> object with modifier keys. The
!    * timestamp for this event is initialized by invoking
!    * {@link java.awt.EventQueue#getMostRecentEventTime()}.
     * <p>
     * Note that passing in an invalid <code>id</code> results in unspecified
     * behavior.
     *
     * @param source    the object that originated the event
     * @param id        an integer that identifies the event
     * @param command   a string that may specify a command (possibly one 
     *                  of several) associated with the event
     * @param modifiers the modifier keys held down during this action
     */
    public ActionEvent(Object source, int id, String command, int modifiers);


Add the following method to java.awt.event.InvocationEvent:

    /**
     * Returns the timestamp of when this event occurred.
     *
     * @return this event's timestamp
     * @since 1.4
     */
    public long getWhen();

    /**
     * Initializes the <code>when</code> field if it is not present in the
     * object input stream. In that case, the field will be initialized by
     * invoking {@link java.awt.EventQueue#getMostRecentEventTime()}.
     */
    private void readObject(ObjectInputStream s) throws
	ClassNotFoundException, IOException;


Modify the following existing methods of java.awt.event.InvocationEvent as
follows:

    /**
     * Constructs an <code>InvocationEvent</code> with the specified
     * source which will execute the runnable's <code>run</code>
!    * method when dispatched. The timestamp for this event is initialized by
!    * invoking {@link java.awt.EventQueue#getMostRecentEventTime()}.
     *
     * @param source    the <code>Object</code> that originated the event
     * @param runnable  the <code>Runnable</code> whose <code>run</code>
     *                  method will be executed
     */
    public InvocationEvent(Object source, Runnable runnable);

    /**
     * Constructs an <code>InvocationEvent</code> with the specified source
     * which will execute the runnable's <code>run</code> method when
     * dispatched. If notifier is non-<code>null</code>,
     * <code>notifyAll()</code> will be called on it immediately after
!    * <code>run</code> returns. The timestamp for this event is initialized by
!    * invoking {@link java.awt.EventQueue#getMostRecentEventTime()}.
     *
     * @param source            the <code>Object</code> that originated
     *                          the event
     * @param runnable          the <code>Runnable</code> whose
     *                          <code>run</code> method will be
     *                          executed
     * @param notifier          the Object whose <code>notifyAll</code>
     *                          method will be called after
     *                          <code>Runnable.run</code> has returned
     * @param catchExceptions   specifies whether <code>dispatch</code>
     *                          should catch Exception when executing
     *                          the <code>Runnable</code>'s <code>run</code>
     *                          method, or should instead propagate those
     *                          Exceptions to the EventDispatchThread's
     *                          dispatch loop
     */
    public InvocationEvent(Object source, Runnable runnable, Object notifier,
                           boolean catchExceptions);


Add the following methods to java.awt.event.InputMethodEvent:

    /**
     * Constructs an <code>InputMethodEvent</code> with the specified source
     * component, type, time, text, caret, and visiblePosition.
     * <p>
     * The offsets of caret and visiblePosition are relative to the current
     * composed text; that is, the composed text within <code>text</code> if
     * this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event, the composed
     * text within the <code>text</code> of the preceding
     * <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise.
     *
     * @param source the object where the event originated
     * @param id the event type
     * @param when a long integer that specifies the time the event occurred
     * @param text the combined committed and composed text,
     *      committed text first; must be <code>null</code>
     *      when the event type is <code>CARET_POSITION_CHANGED</code>;
     *      may be <code>null</code> for
     *      <code>INPUT_METHOD_TEXT_CHANGED</code> if there's no
     *      committed or composed text
     * @param committedCharacterCount the number of committed
     *      characters in the text
     * @param caret the caret (a.k.a. insertion point);
     *      <code>null</code> if there's no caret within current
     *      composed text
     * @param visiblePosition the position that's most important
     *      to be visible; <code>null</code> if there's no
     *      recommendation for a visible position within current
     *      composed text
     * @exception IllegalArgumentException if <code>id</code> is not
     *      in the range
     *      <code>INPUT_METHOD_FIRST</code>..<code>INPUT_METHOD_LAST</code>;
     *      or if id is <code>CARET_POSITION_CHANGED</code> and
     *      <code>text</code> is not <code>null</code>;
     *      or if <code>committedCharacterCount</code> is not in the range
     *      <code>0</code>..<code>(text.getEndIndex() - text.getBeginIndex())</code>
     *
     * @since 1.4
     */
    public InputMethodEvent(Component source, int id, long when,
                            AttributedCharacterIterator text,
                            int committedCharacterCount, TextHitInfo caret,
                            TextHitInfo visiblePosition);

    /**
     * Returns the timestamp of when this event occurred.
     *
     * @return this event's timestamp
     * @since 1.4
     */
    public long getWhen();

    /**
     * Initializes the <code>when</code> field if it is not present in the
     * object input stream. In that case, the field will be initialized by
     * invoking {@link java.awt.EventQueue#getMostRecentEventTime()}.
     */
    private void readObject(ObjectInputStream s) throws
	ClassNotFoundException, IOException;


Modify the specification of the following existing methods on
java.awt.event.InputMethodEvent as follows:

    /**
     * Constructs an <code>InputMethodEvent</code> with the specified source
     * component, type, text, caret, and visiblePosition.
     * <p>
     * The offsets of caret and visiblePosition are relative to the current
     * composed text; that is, the composed text within <code>text</code> if
     * this is an <code>INPUT_METHOD_TEXT_CHANGED</code> event, the composed
     * text within the <code>text</code> of the preceding
!    * <code>INPUT_METHOD_TEXT_CHANGED</code> event otherwise. The time stamp
!    * for this event is initialized by invoking
!    * {@link java.awt.EventQueue#getMostRecentEventTime()}.
     *
     * @param source the object where the event originated
     * @param id the event type
     * @param text the combined committed and composed text,
     *      committed text first; must be <code>null</code>
     *      when the event type is <code>CARET_POSITION_CHANGED</code>;
     *      may be <code>null</code> for
     *      <code>INPUT_METHOD_TEXT_CHANGED</code> if there's no
     *      committed or composed text
     * @param committedCharacterCount the number of committed
     *      characters in the text
     * @param caret the caret (a.k.a. insertion point);
     *      <code>null</code> if there's no caret within current
     *      composed text
     * @param visiblePosition the position that's most important
     *      to be visible; <code>null</code> if there's no
     *      recommendation for a visible position within current
     *      composed text
     * @exception IllegalArgumentException if <code>id</code> is not
     *      in the range
     *      <code>INPUT_METHOD_FIRST</code>..<code>INPUT_METHOD_LAST</code>;
     *      or if id is <code>CARET_POSITION_CHANGED</code> and
     *      <code>text</code> is not <code>null</code>;
     *      or if <code>committedCharacterCount</code> is not in the range
     *      <code>0</code>..<code>(text.getEndIndex() - text.getBeginIndex())</code>
     */

                                     
2004-06-11
CONVERTED DATA

BugTraq+ Release Management Values

COMMIT TO FIX:
merlin-beta2

FIXED IN:
merlin-beta2

INTEGRATED IN:
merlin-beta2


                                     
2004-06-14



Hardware and Software, Engineered to Work Together