8154434: Open the request focus methods of the java.awt.Component which accept FocusEvent.Cause
Reviewed-by: azvegint
--- 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