8154434: Open the request focus methods of the java.awt.Component which accept FocusEvent.Cause
authorssadetsky
Wed, 19 Oct 2016 11:51:40 +0300
changeset 41805 d30817604de5
parent 41804 9b7750392368
child 41806 91176d55df60
8154434: Open the request focus methods of the java.awt.Component which accept FocusEvent.Cause Reviewed-by: azvegint
jdk/src/java.desktop/share/classes/java/awt/Component.java
jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java
jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java
jdk/test/java/awt/Focus/RequestFocusByCause/RequestFocusByCauseTest.java
--- a/jdk/src/java.desktop/share/classes/java/awt/Component.java	Tue Oct 18 13:06:59 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/java/awt/Component.java	Wed Oct 19 11:51:40 2016 +0300
@@ -851,8 +851,8 @@
             {
                 comp.setGraphicsConfiguration(gc);
             }
-            public boolean requestFocus(Component comp, FocusEvent.Cause cause) {
-                return comp.requestFocus(cause);
+            public void requestFocus(Component comp, FocusEvent.Cause cause) {
+                comp.requestFocus(cause);
             }
             public boolean canBeFocusOwner(Component comp) {
                 return comp.canBeFocusOwner();
@@ -7511,8 +7511,51 @@
         requestFocusHelper(false, true);
     }
 
-    boolean requestFocus(FocusEvent.Cause cause) {
-        return requestFocusHelper(false, true, cause);
+
+    /**
+     * Requests by the reason of {@code cause} that this Component get the input
+     * focus, and that this Component's top-level ancestor become the
+     * focused Window. This component must be displayable, focusable, visible
+     * and all of its ancestors (with the exception of the top-level Window)
+     * must be visible for the request to be granted. Every effort will be
+     * made to honor the request; however, in some cases it may be
+     * impossible to do so. Developers must never assume that this
+     * Component is the focus owner until this Component receives a
+     * FOCUS_GAINED event.
+     * <p>
+     * The focus request effect may also depend on the provided
+     * cause value. If this request is succeed the {@code FocusEvent}
+     * generated in the result will receive the cause value specified as the
+     * argument of method. If this request is denied because this Component's
+     * top-level Window cannot become the focused Window, the request will be
+     * remembered and will be granted when the Window is later focused by the
+     * user.
+     * <p>
+     * This method cannot be used to set the focus owner to no Component at
+     * all. Use {@code KeyboardFocusManager.clearGlobalFocusOwner()}
+     * instead.
+     * <p>
+     * Because the focus behavior of this method is platform-dependent,
+     * developers are strongly encouraged to use
+     * {@code requestFocusInWindow(FocusEvent.Cause)} when possible.
+     *
+     * <p>Note: Not all focus transfers result from invoking this method. As
+     * such, a component may receive focus without this or any of the other
+     * {@code requestFocus} methods of {@code Component} being invoked.
+     *
+     * @param  cause the cause why the focus is requested
+     * @see FocusEvent
+     * @see FocusEvent.Cause
+     * @see #requestFocusInWindow(FocusEvent.Cause)
+     * @see java.awt.event.FocusEvent
+     * @see #addFocusListener
+     * @see #isFocusable
+     * @see #isDisplayable
+     * @see KeyboardFocusManager#clearGlobalFocusOwner
+     * @since 9
+     */
+    public void requestFocus(FocusEvent.Cause cause) {
+        requestFocusHelper(false, true, cause);
     }
 
     /**
@@ -7578,9 +7621,77 @@
         return requestFocusHelper(temporary, true);
     }
 
-    boolean requestFocus(boolean temporary, FocusEvent.Cause cause) {
+    /**
+     * Requests by the reason of {@code cause} that this {@code Component} get
+     * the input focus, and that this {@code Component}'s top-level ancestor
+     * become the focused {@code Window}. This component must be
+     * displayable, focusable, visible and all of its ancestors (with
+     * the exception of the top-level Window) must be visible for the
+     * request to be granted. Every effort will be made to honor the
+     * request; however, in some cases it may be impossible to do
+     * so. Developers must never assume that this component is the
+     * focus owner until this component receives a FOCUS_GAINED
+     * event. If this request is denied because this component's
+     * top-level window cannot become the focused window, the request
+     * will be remembered and will be granted when the window is later
+     * focused by the user.
+     * <p>
+     * This method returns a boolean value. If {@code false} is returned,
+     * the request is <b>guaranteed to fail</b>. If {@code true} is
+     * returned, the request will succeed <b>unless</b> it is vetoed, or an
+     * extraordinary event, such as disposal of the component's peer, occurs
+     * before the request can be granted by the native windowing system. Again,
+     * while a return value of {@code true} indicates that the request is
+     * likely to succeed, developers must never assume that this component is
+     * the focus owner until this component receives a FOCUS_GAINED event.
+     * <p>
+     * The focus request effect may also depend on the provided
+     * cause value. If this request is succeed the {FocusEvent}
+     * generated in the result will receive the cause value specified as the
+     * argument of the method.
+     * <p>
+     * This method cannot be used to set the focus owner to no component at
+     * all. Use {@code KeyboardFocusManager.clearGlobalFocusOwner}
+     * instead.
+     * <p>
+     * Because the focus behavior of this method is platform-dependent,
+     * developers are strongly encouraged to use
+     * {@code requestFocusInWindow} when possible.
+     * <p>
+     * Every effort will be made to ensure that {@code FocusEvent}s
+     * generated as a
+     * result of this request will have the specified temporary value. However,
+     * because specifying an arbitrary temporary state may not be implementable
+     * on all native windowing systems, correct behavior for this method can be
+     * guaranteed only for lightweight {@code Component}s.
+     * This method is not intended
+     * for general use, but exists instead as a hook for lightweight component
+     * libraries, such as Swing.
+     * <p>
+     * Note: Not all focus transfers result from invoking this method. As
+     * such, a component may receive focus without this or any of the other
+     * {@code requestFocus} methods of {@code Component} being invoked.
+     *
+     * @param temporary true if the focus change is temporary,
+     *        such as when the window loses the focus; for
+     *        more information on temporary focus changes see the
+     *<a href="../../java/awt/doc-files/FocusSpec.html">Focus Specification</a>
+     *
+     * @param  cause the cause why the focus is requested
+     * @return {@code false} if the focus change request is guaranteed to
+     *         fail; {@code true} if it is likely to succeed
+     * @see FocusEvent
+     * @see FocusEvent.Cause
+     * @see #addFocusListener
+     * @see #isFocusable
+     * @see #isDisplayable
+     * @see KeyboardFocusManager#clearGlobalFocusOwner
+     * @since 9
+     */
+    protected boolean requestFocus(boolean temporary, FocusEvent.Cause cause) {
         return requestFocusHelper(temporary, true, cause);
     }
+
     /**
      * Requests that this Component get the input focus, if this
      * Component's top-level ancestor is already the focused
@@ -7629,7 +7740,59 @@
         return requestFocusHelper(false, false);
     }
 
-    boolean requestFocusInWindow(FocusEvent.Cause cause) {
+    /**
+     * Requests by the reason of {@code cause} that this Component get the input
+     * focus, if this Component's top-level ancestor is already the focused
+     * Window. This component must be displayable, focusable, visible
+     * and all of its ancestors (with the exception of the top-level
+     * Window) must be visible for the request to be granted. Every
+     * effort will be made to honor the request; however, in some
+     * cases it may be impossible to do so. Developers must never
+     * assume that this Component is the focus owner until this
+     * Component receives a FOCUS_GAINED event.
+     * <p>
+     * This method returns a boolean value. If {@code false} is returned,
+     * the request is <b>guaranteed to fail</b>. If {@code true} is
+     * returned, the request will succeed <b>unless</b> it is vetoed, or an
+     * extraordinary event, such as disposal of the Component's peer, occurs
+     * before the request can be granted by the native windowing system. Again,
+     * while a return value of {@code true} indicates that the request is
+     * likely to succeed, developers must never assume that this Component is
+     * the focus owner until this Component receives a FOCUS_GAINED event.
+     * <p>
+     * The focus request effect may also depend on the provided
+     * cause value. If this request is succeed the {@code FocusEvent}
+     * generated in the result will receive the cause value specified as the
+     * argument of the method.
+     * <p>
+     * This method cannot be used to set the focus owner to no Component at
+     * all. Use {@code KeyboardFocusManager.clearGlobalFocusOwner()}
+     * instead.
+     * <p>
+     * The focus behavior of this method can be implemented uniformly across
+     * platforms, and thus developers are strongly encouraged to use this
+     * method over {@code requestFocus(FocusEvent.Cause)} when possible.
+     * Code which relies on {@code requestFocus(FocusEvent.Cause)} may exhibit
+     * different focus behavior on different platforms.
+     *
+     * <p>Note: Not all focus transfers result from invoking this method. As
+     * such, a component may receive focus without this or any of the other
+     * {@code requestFocus} methods of {@code Component} being invoked.
+     *
+     * @param  cause the cause why the focus is requested
+     * @return {@code false} if the focus change request is guaranteed to
+     *         fail; {@code true} if it is likely to succeed
+     * @see #requestFocus(FocusEvent.Cause)
+     * @see FocusEvent
+     * @see FocusEvent.Cause
+     * @see java.awt.event.FocusEvent
+     * @see #addFocusListener
+     * @see #isFocusable
+     * @see #isDisplayable
+     * @see KeyboardFocusManager#clearGlobalFocusOwner
+     * @since 9
+     */
+    public boolean requestFocusInWindow(FocusEvent.Cause cause) {
         return requestFocusHelper(false, false, cause);
     }
 
--- a/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java	Tue Oct 18 13:06:59 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/AWTAccessor.java	Wed Oct 19 11:51:40 2016 +0300
@@ -107,7 +107,7 @@
         /*
          * Requests focus to the component.
          */
-        boolean requestFocus(Component comp, Cause cause);
+        void requestFocus(Component comp, Cause cause);
         /*
          * Determines if the component can gain focus.
          */
@@ -1392,4 +1392,4 @@
         AWTAccessor.dropTargetContextAccessor = accessor;
     }
 
-}
\ No newline at end of file
+}
--- a/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java	Tue Oct 18 13:06:59 2016 -0700
+++ b/jdk/src/java.desktop/share/classes/sun/awt/KeyboardFocusManagerPeerImpl.java	Wed Oct 19 11:51:40 2016 +0300
@@ -142,8 +142,8 @@
     }
 
     // WARNING: Don't call it on the Toolkit thread.
-    public static boolean requestFocusFor(Component target, FocusEvent.Cause cause) {
-        return AWTAccessor.getComponentAccessor().requestFocus(target, cause);
+    public static void requestFocusFor(Component target, FocusEvent.Cause cause) {
+        AWTAccessor.getComponentAccessor().requestFocus(target, cause);
     }
 
     // WARNING: Don't call it on the Toolkit thread.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/Focus/RequestFocusByCause/RequestFocusByCauseTest.java	Wed Oct 19 11:51:40 2016 +0300
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+  @test
+  @bug 8154434
+  @summary Open the request focus methods of the java.awt.Component which accept
+           FocusEvent.Cause
+  @run main RequestFocusByCauseTest
+*/
+
+import java.awt.*;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+
+public class RequestFocusByCauseTest {
+    static boolean success;
+
+    public static void main(String[] args) throws Exception {
+        testRequestFocusCause();
+        testRequestFocusTemporaryCause();
+        testRequestFocusInWindowCause();
+        System.out.println("ok");
+    }
+
+    private static void testRequestFocusCause() throws AWTException {
+        Frame frame = new Frame();
+        Component c = new Button();
+        frame.add(new Button());
+        frame.add(c);
+        c.addFocusListener(new FocusListener() {
+            @Override
+            public void focusGained(FocusEvent e) {
+                success = e.getCause() == FocusEvent.Cause.UNEXPECTED;
+            }
+
+            @Override
+            public void focusLost(FocusEvent e) {}
+        });
+        Robot robot = new Robot();
+
+        try {
+            frame.setVisible(true);
+            robot.waitForIdle();
+            robot.delay(200);
+            success = false;
+
+            c.requestFocus(FocusEvent.Cause.UNEXPECTED);
+            robot.waitForIdle();
+            robot.delay(200);
+            if(!success) {
+                throw new RuntimeException("request failed");
+            }
+        } finally {
+            frame.dispose();
+        }
+    }
+
+    private static void testRequestFocusTemporaryCause() throws AWTException {
+        Frame frame = new Frame();
+        frame.add(new Button() {
+            @Override
+            protected boolean requestFocus(boolean temporary,
+                                                       FocusEvent.Cause cause) {
+                success = cause == FocusEvent.Cause.ROLLBACK;
+                return super.requestFocus(temporary, cause);
+            }
+        });
+        Component c = new Button() {
+            @Override
+            public void requestFocus() {
+                super.requestFocus();
+                setFocusable(false);
+            }
+        };
+        frame.add(c);
+        Robot robot = new Robot();
+
+        try {
+            frame.setVisible(true);
+            robot.waitForIdle();
+            robot.delay(200);
+
+            success = false;
+            c.requestFocus();
+            robot.waitForIdle();
+            robot.delay(200);
+
+
+            if(!success) {
+                throw new RuntimeException("rollback request is not triggered");
+            }
+        } finally {
+            frame.dispose();
+        }
+    }
+
+    private static void testRequestFocusInWindowCause() throws AWTException {
+        Frame frame = new Frame();
+        Component c = new Button();
+        frame.add(new Button());
+        frame.add(c);
+        c.addFocusListener(new FocusListener() {
+            @Override
+            public void focusGained(FocusEvent e) {
+                success = e.getCause() == FocusEvent.Cause.UNEXPECTED;
+            }
+
+            @Override
+            public void focusLost(FocusEvent e) {
+            }
+        });
+        Robot robot = new Robot();
+
+        try {
+            frame.setVisible(true);
+            robot.waitForIdle();
+            robot.delay(200);
+            success = false;
+
+            c.requestFocusInWindow(FocusEvent.Cause.UNEXPECTED);
+            robot.waitForIdle();
+            robot.delay(200);
+            if (!success) {
+                throw new RuntimeException("request in window failed");
+            }
+        } finally {
+            frame.dispose();
+        }
+    }
+}
\ No newline at end of file