6607170: Focus not set by requestFocus
Fixing/refactoring focus auto-transfer mechanism. Reviewed-by: son
This commit is contained in:
parent
5887f56e62
commit
06e3882354
jdk
src
share/classes/java/awt
solaris/classes/sun/awt/X11
windows/native/sun/windows
test/java/awt/Focus/ContainerFocusAutoTransferTest
@ -1327,12 +1327,15 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
KeyboardFocusManager.clearMostRecentFocusOwner(this);
|
||||
synchronized (getTreeLock()) {
|
||||
enabled = false;
|
||||
if (isFocusOwner()) {
|
||||
// A disabled lw container is allowed to contain a focus owner.
|
||||
if ((isFocusOwner() || (containsFocus() && !isLightweight())) &&
|
||||
KeyboardFocusManager.isAutoFocusTransferEnabled())
|
||||
{
|
||||
// Don't clear the global focus owner. If transferFocus
|
||||
// fails, we want the focus to stay on the disabled
|
||||
// Component so that keyboard traversal, et. al. still
|
||||
// makes sense to the user.
|
||||
autoTransferFocus(false);
|
||||
transferFocus(false);
|
||||
}
|
||||
ComponentPeer peer = this.peer;
|
||||
if (peer != null) {
|
||||
@ -1493,8 +1496,8 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
synchronized (getTreeLock()) {
|
||||
visible = false;
|
||||
mixOnHiding(isLightweight());
|
||||
if (containsFocus()) {
|
||||
autoTransferFocus(true);
|
||||
if (containsFocus() && KeyboardFocusManager.isAutoFocusTransferEnabled()) {
|
||||
transferFocus(true);
|
||||
}
|
||||
ComponentPeer peer = this.peer;
|
||||
if (peer != null) {
|
||||
@ -6578,12 +6581,8 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
}
|
||||
|
||||
synchronized (getTreeLock()) {
|
||||
if (isFocusOwner()
|
||||
&& KeyboardFocusManager.isAutoFocusTransferEnabled()
|
||||
&& !nextFocusHelper())
|
||||
{
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().
|
||||
clearGlobalFocusOwner();
|
||||
if (isFocusOwner() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) {
|
||||
transferFocus(true);
|
||||
}
|
||||
|
||||
if (getContainer() != null && isAddNotifyComplete) {
|
||||
@ -6718,8 +6717,8 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
|
||||
firePropertyChange("focusable", oldFocusable, focusable);
|
||||
if (oldFocusable && !focusable) {
|
||||
if (isFocusOwner()) {
|
||||
autoTransferFocus(true);
|
||||
if (isFocusOwner() && KeyboardFocusManager.isAutoFocusTransferEnabled()) {
|
||||
transferFocus(true);
|
||||
}
|
||||
KeyboardFocusManager.clearMostRecentFocusOwner(this);
|
||||
}
|
||||
@ -7373,69 +7372,6 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
}
|
||||
}
|
||||
|
||||
private void autoTransferFocus(boolean clearOnFailure) {
|
||||
Component toTest = KeyboardFocusManager.
|
||||
getCurrentKeyboardFocusManager().getFocusOwner();
|
||||
if (toTest != this) {
|
||||
if (toTest != null) {
|
||||
toTest.autoTransferFocus(clearOnFailure);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if there are pending focus requests. We shouldn't do
|
||||
// auto-transfer if user has already took care of this
|
||||
// component becoming ineligible to hold focus.
|
||||
if (!KeyboardFocusManager.isAutoFocusTransferEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// the following code will execute only if this Component is the focus
|
||||
// owner
|
||||
|
||||
if (!(isDisplayable() && isVisible() && isEnabled() && isFocusable())) {
|
||||
doAutoTransfer(clearOnFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
toTest = getParent();
|
||||
|
||||
while (toTest != null && !(toTest instanceof Window)) {
|
||||
if (!(toTest.isDisplayable() && toTest.isVisible() &&
|
||||
(toTest.isEnabled() || toTest.isLightweight()))) {
|
||||
doAutoTransfer(clearOnFailure);
|
||||
return;
|
||||
}
|
||||
toTest = toTest.getParent();
|
||||
}
|
||||
}
|
||||
private void doAutoTransfer(boolean clearOnFailure) {
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.log(Level.FINER, "this = " + this + ", clearOnFailure = " + clearOnFailure);
|
||||
}
|
||||
if (clearOnFailure) {
|
||||
if (!nextFocusHelper()) {
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.log(Level.FINER, "clear global focus owner");
|
||||
}
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().
|
||||
clearGlobalFocusOwner();
|
||||
}
|
||||
} else {
|
||||
transferFocus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers the focus to the next component, as though this Component were
|
||||
* the focus owner.
|
||||
* @see #requestFocus()
|
||||
* @since JDK1.1
|
||||
*/
|
||||
public void transferFocus() {
|
||||
nextFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Container which is the focus cycle root of this Component's
|
||||
* focus traversal cycle. Each focus traversal cycle has only a single
|
||||
@ -7475,31 +7411,51 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
return (rootAncestor == container);
|
||||
}
|
||||
|
||||
Container getTraversalRoot() {
|
||||
return getFocusCycleRootAncestor();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers the focus to the next component, as though this Component were
|
||||
* the focus owner.
|
||||
* @see #requestFocus()
|
||||
* @since JDK1.1
|
||||
*/
|
||||
public void transferFocus() {
|
||||
nextFocus();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated As of JDK version 1.1,
|
||||
* replaced by transferFocus().
|
||||
*/
|
||||
@Deprecated
|
||||
public void nextFocus() {
|
||||
nextFocusHelper();
|
||||
transferFocus(false);
|
||||
}
|
||||
|
||||
private boolean nextFocusHelper() {
|
||||
Component toFocus = preNextFocusHelper();
|
||||
boolean transferFocus(boolean clearOnFailure) {
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.log(Level.FINER, "toFocus = " + toFocus);
|
||||
focusLog.finer("clearOnFailure = " + clearOnFailure);
|
||||
}
|
||||
if (isFocusOwner() && toFocus == this) {
|
||||
return false;
|
||||
Component toFocus = getNextFocusCandidate();
|
||||
boolean res = false;
|
||||
if (toFocus != null && !toFocus.isFocusOwner() && toFocus != this) {
|
||||
res = toFocus.requestFocusInWindow(CausedFocusEvent.Cause.TRAVERSAL_FORWARD);
|
||||
}
|
||||
return postNextFocusHelper(toFocus, CausedFocusEvent.Cause.TRAVERSAL_FORWARD);
|
||||
if (clearOnFailure && !res) {
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.finer("clear global focus owner");
|
||||
}
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
|
||||
}
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.finer("returning result: " + res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Container getTraversalRoot() {
|
||||
return getFocusCycleRootAncestor();
|
||||
}
|
||||
|
||||
final Component preNextFocusHelper() {
|
||||
final Component getNextFocusCandidate() {
|
||||
Container rootAncestor = getTraversalRoot();
|
||||
Component comp = this;
|
||||
while (rootAncestor != null &&
|
||||
@ -7511,18 +7467,19 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
rootAncestor = comp.getFocusCycleRootAncestor();
|
||||
}
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.log(Level.FINER, "comp = " + comp + ", root = " + rootAncestor);
|
||||
focusLog.finer("comp = " + comp + ", root = " + rootAncestor);
|
||||
}
|
||||
Component candidate = null;
|
||||
if (rootAncestor != null) {
|
||||
FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy();
|
||||
Component toFocus = policy.getComponentAfter(rootAncestor, comp);
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.log(Level.FINER, "component after is " + toFocus);
|
||||
focusLog.finer("component after is " + toFocus);
|
||||
}
|
||||
if (toFocus == null) {
|
||||
toFocus = policy.getDefaultComponent(rootAncestor);
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.log(Level.FINER, "default component is " + toFocus);
|
||||
focusLog.finer("default component is " + toFocus);
|
||||
}
|
||||
}
|
||||
if (toFocus == null) {
|
||||
@ -7531,23 +7488,12 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
toFocus = applet;
|
||||
}
|
||||
}
|
||||
return toFocus;
|
||||
candidate = toFocus;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static boolean postNextFocusHelper(Component toFocus, CausedFocusEvent.Cause cause) {
|
||||
if (toFocus != null) {
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.log(Level.FINER, "Next component " + toFocus);
|
||||
}
|
||||
boolean res = toFocus.requestFocusInWindow(cause);
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.log(Level.FINER, "Request focus returned " + res);
|
||||
}
|
||||
return res;
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.finer("Focus transfer candidate: " + candidate);
|
||||
}
|
||||
return false;
|
||||
return candidate;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7557,6 +7503,10 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
* @since 1.4
|
||||
*/
|
||||
public void transferFocusBackward() {
|
||||
transferFocusBackward(false);
|
||||
}
|
||||
|
||||
boolean transferFocusBackward(boolean clearOnFailure) {
|
||||
Container rootAncestor = getTraversalRoot();
|
||||
Component comp = this;
|
||||
while (rootAncestor != null &&
|
||||
@ -7567,6 +7517,7 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
comp = rootAncestor;
|
||||
rootAncestor = comp.getFocusCycleRootAncestor();
|
||||
}
|
||||
boolean res = false;
|
||||
if (rootAncestor != null) {
|
||||
FocusTraversalPolicy policy = rootAncestor.getFocusTraversalPolicy();
|
||||
Component toFocus = policy.getComponentBefore(rootAncestor, comp);
|
||||
@ -7574,9 +7525,19 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
toFocus = policy.getDefaultComponent(rootAncestor);
|
||||
}
|
||||
if (toFocus != null) {
|
||||
toFocus.requestFocusInWindow(CausedFocusEvent.Cause.TRAVERSAL_BACKWARD);
|
||||
res = toFocus.requestFocusInWindow(CausedFocusEvent.Cause.TRAVERSAL_BACKWARD);
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.finer("clear global focus owner");
|
||||
}
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
|
||||
}
|
||||
if (focusLog.isLoggable(Level.FINER)) {
|
||||
focusLog.finer("returning result: " + res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7651,6 +7612,20 @@ public abstract class Component implements ImageObserver, MenuContainer,
|
||||
return hasFocus();
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to disallow auto-focus-transfer on disposal of the focus owner
|
||||
* in the process of disposing its parent container.
|
||||
*/
|
||||
private boolean autoFocusTransferOnDisposal = true;
|
||||
|
||||
void setAutoFocusTransferOnDisposal(boolean value) {
|
||||
autoFocusTransferOnDisposal = value;
|
||||
}
|
||||
|
||||
boolean isAutoFocusTransferOnDisposal() {
|
||||
return autoFocusTransferOnDisposal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified popup menu to the component.
|
||||
* @param popup the popup menu to be added to the component.
|
||||
|
@ -2660,9 +2660,26 @@ public class Container extends Component {
|
||||
synchronized (getTreeLock()) {
|
||||
int ncomponents = this.ncomponents;
|
||||
Component component[] = this.component;
|
||||
for (int i = ncomponents-1 ; i >= 0 ; i--) {
|
||||
if( component[i] != null )
|
||||
component[i].removeNotify();
|
||||
for (int i = ncomponents - 1; i >= 0; i--) {
|
||||
if( component[i] != null ) {
|
||||
// Fix for 6607170.
|
||||
// We want to suppress focus change on disposal
|
||||
// of the focused component. But because of focus
|
||||
// is asynchronous, we should suppress focus change
|
||||
// on every component in case it receives native focus
|
||||
// in the process of disposal.
|
||||
component[i].setAutoFocusTransferOnDisposal(false);
|
||||
component[i].removeNotify();
|
||||
component[i].setAutoFocusTransferOnDisposal(true);
|
||||
}
|
||||
}
|
||||
// If some of the children had focus before disposal then it still has.
|
||||
// Auto-transfer focus to the next (or previous) component if auto-transfer
|
||||
// is enabled.
|
||||
if (containsFocus() && KeyboardFocusManager.isAutoFocusTransferEnabledFor(this)) {
|
||||
if (!transferFocus(false)) {
|
||||
transferFocusBackward(true);
|
||||
}
|
||||
}
|
||||
if ( dispatcher != null ) {
|
||||
dispatcher.dispose();
|
||||
|
@ -155,12 +155,13 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager {
|
||||
boolean clearOnFailure)
|
||||
{
|
||||
if (toFocus != vetoedComponent && toFocus.isShowing() && toFocus.isFocusable() &&
|
||||
toFocus.requestFocus(false, CausedFocusEvent.Cause.ROLLBACK)) {
|
||||
toFocus.requestFocus(false, CausedFocusEvent.Cause.ROLLBACK))
|
||||
{
|
||||
return true;
|
||||
} else {
|
||||
Component nextFocus = toFocus.preNextFocusHelper();
|
||||
if (nextFocus != vetoedComponent
|
||||
&& Component.postNextFocusHelper(nextFocus, CausedFocusEvent.Cause.ROLLBACK))
|
||||
Component nextFocus = toFocus.getNextFocusCandidate();
|
||||
if (nextFocus != null && nextFocus != vetoedComponent &&
|
||||
nextFocus.requestFocusInWindow(CausedFocusEvent.Cause.ROLLBACK))
|
||||
{
|
||||
return true;
|
||||
} else if (clearOnFailure) {
|
||||
@ -504,9 +505,16 @@ public class DefaultKeyboardFocusManager extends KeyboardFocusManager {
|
||||
{
|
||||
// we should not accept focus on such component, so reject it.
|
||||
dequeueKeyEvents(-1, newFocusOwner);
|
||||
if (KeyboardFocusManager.isAutoFocusTransferEnabled())
|
||||
{
|
||||
restoreFocus(fe, newFocusedWindow);
|
||||
if (KeyboardFocusManager.isAutoFocusTransferEnabled()) {
|
||||
// If FOCUS_GAINED is for a disposed component (however
|
||||
// it shouldn't happen) its toplevel parent is null. In this
|
||||
// case we have to try to restore focus in the current focused
|
||||
// window (for the details: 6607170).
|
||||
if (newFocusedWindow == null) {
|
||||
restoreFocus(fe, currentFocusedWindow);
|
||||
} else {
|
||||
restoreFocus(fe, newFocusedWindow);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -2578,6 +2578,10 @@ public abstract class KeyboardFocusManager
|
||||
}
|
||||
}
|
||||
|
||||
static boolean isAutoFocusTransferEnabledFor(Component comp) {
|
||||
return isAutoFocusTransferEnabled() && comp.isAutoFocusTransferOnDisposal();
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to process exceptions in dispatching focus event (in focusLost/focusGained callbacks).
|
||||
* @param ex previously caught exception that may be processed right here, or null
|
||||
|
@ -96,12 +96,12 @@ public class XKeyboardFocusManagerPeer implements KeyboardFocusManagerPeer {
|
||||
Component focusOwner = activeWindow.getFocusOwner();
|
||||
if (focusLog.isLoggable(Level.FINE)) focusLog.fine("Clearing global focus owner " + focusOwner);
|
||||
if (focusOwner != null) {
|
||||
XComponentPeer nativePeer = XComponentPeer.getNativeContainer(focusOwner);
|
||||
if (nativePeer != null) {
|
||||
// XComponentPeer nativePeer = XComponentPeer.getNativeContainer(focusOwner);
|
||||
// if (nativePeer != null) {
|
||||
FocusEvent fl = new CausedFocusEvent(focusOwner, FocusEvent.FOCUS_LOST, false, null,
|
||||
CausedFocusEvent.Cause.CLEAR_GLOBAL_FOCUS_OWNER);
|
||||
XWindow.sendEvent(fl);
|
||||
}
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -903,8 +903,27 @@ void AwtComponent::Show()
|
||||
|
||||
void AwtComponent::Hide()
|
||||
{
|
||||
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
|
||||
jobject peer = GetPeer(env);
|
||||
BOOL oldValue = sm_suppressFocusAndActivation;
|
||||
m_visible = false;
|
||||
|
||||
// On disposal the focus owner actually loses focus at the moment of hiding.
|
||||
// So, focus change suppression (if requested) should be made here.
|
||||
if (GetHWnd() == sm_focusOwner &&
|
||||
!JNU_CallMethodByName(env, NULL, peer, "isAutoFocusTransferOnDisposal", "()Z").z)
|
||||
{
|
||||
sm_suppressFocusAndActivation = TRUE;
|
||||
// The native system may autotransfer focus on hiding to the parent
|
||||
// of the component. Nevertheless this focus change won't be posted
|
||||
// to the Java level, we're better to avoid this. Anyway, after
|
||||
// the disposal focus should be requested to the right component.
|
||||
::SetFocus(NULL);
|
||||
sm_focusOwner = NULL;
|
||||
}
|
||||
::ShowWindow(GetHWnd(), SW_HIDE);
|
||||
|
||||
sm_suppressFocusAndActivation = oldValue;
|
||||
}
|
||||
|
||||
BOOL
|
||||
|
243
jdk/test/java/awt/Focus/ContainerFocusAutoTransferTest/ContainerFocusAutoTransferTest.java
Normal file
243
jdk/test/java/awt/Focus/ContainerFocusAutoTransferTest/ContainerFocusAutoTransferTest.java
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright 2008 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
@test
|
||||
@bug 6607170
|
||||
@summary Tests for focus-auto-transfer.
|
||||
@author Anton Tarasov: area=awt-focus
|
||||
@library ../../regtesthelpers
|
||||
@build Util
|
||||
@run main ContainerFocusAutoTransferTest
|
||||
*/
|
||||
|
||||
import java.applet.Applet;
|
||||
import java.awt.AWTEvent;
|
||||
import java.awt.Component;
|
||||
import java.awt.ComponentOrientation;
|
||||
import java.awt.DefaultKeyboardFocusManager;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Robot;
|
||||
import java.awt.Color;
|
||||
import java.awt.FlowLayout;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.AWTEventListener;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.WindowEvent;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import test.java.awt.regtesthelpers.Util;
|
||||
|
||||
public class ContainerFocusAutoTransferTest extends Applet {
|
||||
Robot robot;
|
||||
TestFrame frame;
|
||||
KeyboardFocusManager kfm;
|
||||
enum TestCase {
|
||||
REMOVAL { public String toString() { return "removal"; } },
|
||||
HIDING { public String toString() { return "hiding"; } },
|
||||
DISABLING { public String toString() { return "disabling"; } },
|
||||
DEFOCUSING { public String toString() { return "defocusing"; } };
|
||||
public abstract String toString();
|
||||
};
|
||||
|
||||
public static void main(String[] args) {
|
||||
ContainerFocusAutoTransferTest app = new ContainerFocusAutoTransferTest();
|
||||
app.init();
|
||||
app.start();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
robot = Util.createRobot();
|
||||
kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
|
||||
public void eventDispatched(AWTEvent event) {
|
||||
System.out.println("--> " + event);
|
||||
}
|
||||
}, FocusEvent.FOCUS_EVENT_MASK | WindowEvent.WINDOW_FOCUS_EVENT_MASK);
|
||||
}
|
||||
|
||||
public void start() {
|
||||
System.out.println("*** TEST #1 ***");
|
||||
test(TestCase.HIDING);
|
||||
|
||||
System.out.println("*** TEST #2 ***");
|
||||
test(TestCase.REMOVAL);
|
||||
|
||||
System.out.println("*** TEST #3 ***");
|
||||
test3(TestCase.DISABLING);
|
||||
|
||||
System.out.println("*** TEST #4 ***");
|
||||
test3(TestCase.DEFOCUSING);
|
||||
|
||||
System.out.println("*** TEST #5 ***");
|
||||
test4();
|
||||
|
||||
System.out.println("Test passed.");
|
||||
}
|
||||
|
||||
void test(final TestCase t) {
|
||||
showFrame();
|
||||
test1(t); // Test for correct auto-transfer
|
||||
test2(t); // Test for clearing focus
|
||||
}
|
||||
|
||||
void test1(final TestCase t) {
|
||||
Runnable action = new Runnable() {
|
||||
public void run() {
|
||||
KeyboardFocusManager.setCurrentKeyboardFocusManager(new TestKFM());
|
||||
if (t == TestCase.REMOVAL) {
|
||||
frame.remove(frame.panel0);
|
||||
|
||||
} else if (t == TestCase.HIDING) {
|
||||
frame.panel0.setVisible(false);
|
||||
}
|
||||
frame.repaint();
|
||||
}
|
||||
};
|
||||
if (!Util.trackFocusGained(frame.b3, action, 2000, false)) {
|
||||
throw new TestFailedException(t + ": focus wasn't transfered as expected!");
|
||||
}
|
||||
KeyboardFocusManager.setCurrentKeyboardFocusManager(kfm);
|
||||
}
|
||||
|
||||
void test2(TestCase t) {
|
||||
frame.setFocusable(false); // exclude it from the focus cycle
|
||||
if (t == TestCase.REMOVAL) {
|
||||
frame.remove(frame.panel1);
|
||||
|
||||
} else if (t == TestCase.HIDING) {
|
||||
frame.panel1.setVisible(false);
|
||||
}
|
||||
frame.repaint();
|
||||
Util.waitForIdle(robot);
|
||||
if (kfm.getFocusOwner() != null) {
|
||||
throw new TestFailedException(t + ": focus wasn't cleared!");
|
||||
}
|
||||
}
|
||||
|
||||
void test3(final TestCase t) {
|
||||
showFrame();
|
||||
Runnable action = new Runnable() {
|
||||
public void run() {
|
||||
if (t == TestCase.DISABLING) {
|
||||
frame.b0.setEnabled(false);
|
||||
|
||||
} else if (t == TestCase.DEFOCUSING) {
|
||||
frame.b0.setFocusable(false);
|
||||
}
|
||||
}};
|
||||
if (!Util.trackFocusGained(frame.b1, action, 2000, false)) {
|
||||
throw new TestFailedException(t + ": focus wasn't transfered as expected!");
|
||||
}
|
||||
}
|
||||
|
||||
void test4() {
|
||||
showFrame();
|
||||
frame.setFocusableWindowState(false);
|
||||
Util.waitForIdle(robot);
|
||||
if (kfm.getFocusOwner() != null) {
|
||||
throw new TestFailedException("defocusing the frame: focus wasn't cleared!");
|
||||
}
|
||||
}
|
||||
|
||||
void showFrame() {
|
||||
if (frame != null) {
|
||||
frame.dispose();
|
||||
Util.waitForIdle(robot);
|
||||
}
|
||||
frame = new TestFrame();
|
||||
frame.setVisible(true);
|
||||
Util.waitTillShown(frame);
|
||||
|
||||
if (!frame.b0.hasFocus()) {
|
||||
Util.clickOnComp(frame.b0, robot);
|
||||
Util.waitForIdle(robot);
|
||||
if (!frame.b0.hasFocus()) {
|
||||
throw new TestErrorException("couldn't set focus on " + frame.b2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TestKFM extends DefaultKeyboardFocusManager {
|
||||
public boolean dispatchEvent(AWTEvent e) {
|
||||
if (e.getID() == FocusEvent.FOCUS_GAINED) {
|
||||
System.out.println(e);
|
||||
Component src = (Component)e.getSource();
|
||||
if (src == frame.b1 || src == frame.b2) {
|
||||
throw new TestFailedException("wrong focus transfer on removal!");
|
||||
}
|
||||
}
|
||||
return super.dispatchEvent(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TestFrame extends JFrame {
|
||||
public JPanel panel0 = new JPanel();
|
||||
public JPanel panel1 = new JPanel();
|
||||
public JButton b0 = new JButton("b0");
|
||||
public JButton b1 = new JButton("b1");
|
||||
public JButton b2 = new JButton("b2");
|
||||
public JButton b3 = new JButton("b3");
|
||||
public JButton b4 = new JButton("b4");
|
||||
|
||||
public TestFrame() {
|
||||
super("TestFrame");
|
||||
|
||||
// The change of the orientation and the reverse order of
|
||||
// adding the buttons to the panel is because in Container.removeNotify()
|
||||
// the child components are removed in the reverse order.
|
||||
// We want that the focus owner (b0) would be removed first and
|
||||
// that the next traversable component would be b1.
|
||||
panel0.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
|
||||
panel0.add(b2);
|
||||
panel0.add(b1);
|
||||
panel0.add(b0);
|
||||
|
||||
panel1.add(b3);
|
||||
panel1.add(b4);
|
||||
|
||||
setLayout(new FlowLayout());
|
||||
add(panel0);
|
||||
add(panel1);
|
||||
pack();
|
||||
|
||||
panel0.setBackground(Color.red);
|
||||
panel1.setBackground(Color.blue);
|
||||
}
|
||||
}
|
||||
|
||||
// Thrown when the behavior being verified is found wrong.
|
||||
class TestFailedException extends RuntimeException {
|
||||
TestFailedException(String msg) {
|
||||
super("Test failed: " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Thrown when an error not related to the behavior being verified is encountered.
|
||||
class TestErrorException extends RuntimeException {
|
||||
TestErrorException(String msg) {
|
||||
super("Unexpected error: " + msg);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user