/*******************************************************************************
* Copyright (c) 2007-2008 SAS Institute Inc., ILOG S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* SAS Institute Inc. - initial API and implementation
* ILOG S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.albireo.internal;
import java.awt.Component;
import java.awt.Container;
import java.awt.KeyboardFocusManager;
import java.awt.Window;
import java.awt.event.ContainerEvent;
import java.awt.event.ContainerListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Event;
/**
* This class contains utility functions for debugging focus issues relating
* to the SWT_AWT bridge.
* <p>
* Debugging focus issues cannot be done in a debugger running on the same
* machine, because the interactions with the debugger often cause the
* application window to be deactivated. Therefore a println based approach
* has been adopted.
* <p>
* There are four kinds of events:
* <ul>
* <li>SWT focus events relating to the IlvSwingControl.</li>
* <li>AWT window focus events relating to the topmost window under the
* IlvSwingControl.</li>
* <li>AWT focus events relating to components inside that window.</li>
* <li>Property change events of the AWT
* <code>KeyboardFocusManager</code>.</li>
* </ul>
*/
public class FocusDebugging {
/**
* Adds listeners for debugging the three first kinds of focus events.
*/
public static void addFocusDebugListeners(org.eclipse.swt.widgets.Composite control,
Container topLevelComponent) {
control.addFocusListener(_SWTFocusListener);
control.addListener(SWT.Activate, _SWTActivationListener);
control.addListener(SWT.Deactivate, _SWTActivationListener);
if (topLevelComponent instanceof Window)
((Window)topLevelComponent).addWindowFocusListener(_AWTWindowFocusListener);
addFocusListenerToTree(topLevelComponent);
}
/**
* Shows focus events on the SWT side.
*/
private static class SWTFocusListener implements org.eclipse.swt.events.FocusListener {
public void focusGained(org.eclipse.swt.events.FocusEvent event) {
System.err.println("@"+System.currentTimeMillis()
+" SWT focus gained "+event.getSource().hashCode());
}
public void focusLost(org.eclipse.swt.events.FocusEvent event) {
System.err.println("@"+System.currentTimeMillis()
+" SWT focus lost "+event.getSource().hashCode());
}
}
private static SWTFocusListener _SWTFocusListener = new SWTFocusListener();
/**
* Shows activation events on the SWT side. Note: events that are eaten by the filter
* in FocusHander will not be displayed here.
*/
private static class SWTActivationListener implements org.eclipse.swt.widgets.Listener {
public void handleEvent(Event event) {
String name = null;
switch (event.type) {
case SWT.Deactivate:
name = "Deactivate";
break;
case SWT.Activate:
name = "Activate";
break;
}
System.err.println("@"+System.currentTimeMillis() +
" SWT Event: " + name + " " + System.identityHashCode(event.widget));
}
}
private static SWTActivationListener _SWTActivationListener = new SWTActivationListener();
/**
* Shows focus events on the top-level window on the AWT side.
*/
private static class AWTWindowFocusListener implements WindowFocusListener {
private void showKFMStatus(Window window) {
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
System.err.println(" permanentFocusOwner: "+kfm.getPermanentFocusOwner());
System.err.println(" focusOwner: "+kfm.getFocusOwner());
System.err.println(" window's focusOwner: "+window.getFocusOwner());
}
public void windowGainedFocus(WindowEvent event) {
System.err.println("@"+System.currentTimeMillis()
+" AWT focus gained by window "+event.getWindow());
showKFMStatus(event.getWindow());
}
public void windowLostFocus(WindowEvent event) {
System.err.println("@"+System.currentTimeMillis()
+" AWT focus lost by window "+event.getWindow());
showKFMStatus(event.getWindow());
}
}
private static AWTWindowFocusListener _AWTWindowFocusListener = new AWTWindowFocusListener();
/**
* Shows focus events on a given component on the AWT side.
*/
private static class AWTFocusListener implements FocusListener {
public void focusGained(FocusEvent event) {
System.err.println("@"+System.currentTimeMillis()
+" AWT focus gained "+event.getComponent());
}
public void focusLost(FocusEvent event) {
System.err.println("@"+System.currentTimeMillis()
+" AWT focus lost "+event.getComponent());
}
}
private static AWTFocusListener _AWTFocusListener = new AWTFocusListener();
/**
* Attaches the AWTFocusListener on each of the components in the component
* tree under the given component.
*/
private static class AWTContainerListener implements ContainerListener {
public void componentAdded(ContainerEvent event) {
addFocusListenerToTree(event.getChild());
}
public void componentRemoved(ContainerEvent event) {
removeFocusListenerFromTree(event.getChild());
}
}
private static AWTContainerListener _AWTContainerListener = new AWTContainerListener();
static void addFocusListenerToTree(Component comp) {
comp.addFocusListener(_AWTFocusListener);
if (comp instanceof Container) {
Container cont = (Container)comp;
// Remember to add the listener to child components that are added later.
cont.addContainerListener(_AWTContainerListener);
// Recurse across all child components that are already in the tree now.
int n = cont.getComponentCount();
for (int i = 0; i < n; i++)
addFocusListenerToTree(cont.getComponent(i));
}
}
static void removeFocusListenerFromTree(Component comp) {
// The exact opposite of addFocusListenerToTree.
comp.removeFocusListener(_AWTFocusListener);
if (comp instanceof Container) {
Container cont = (Container)comp;
cont.removeContainerListener(_AWTContainerListener);
int n = cont.getComponentCount();
for (int i = 0; i < n; i++)
removeFocusListenerFromTree(cont.getComponent(i));
}
}
// ------------------------------------------------------------------------
/**
* Enables logging of events,
* from the AWT <code>KeyboardFocusManager</code> singleton.
*/
public static void enableKeyboardFocusManagerLogging() {
enableFinest("java.awt.focus.KeyboardFocusManager");
enableFinest("java.awt.focus.DefaultKeyboardFocusManager");
}
private static void enableFinest(String name) {
Logger logger = Logger.getLogger(name);
logger.setLevel(Level.FINEST);
ConsoleHandler handler = new ConsoleHandler();
handler.setLevel(Level.FINEST);
logger.addHandler(handler);
}
}