/*******************************************************************************
* 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 ( final org.eclipse.swt.widgets.Composite control, final 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 ( final org.eclipse.swt.events.FocusEvent event )
{
System.err.println ( "@" + System.currentTimeMillis () + " SWT focus gained " + event.getSource ().hashCode () );
}
public void focusLost ( final 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 ( final 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 ( final Window window )
{
final 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 ( final WindowEvent event )
{
System.err.println ( "@" + System.currentTimeMillis () + " AWT focus gained by window " + event.getWindow () );
showKFMStatus ( event.getWindow () );
}
public void windowLostFocus ( final 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 ( final FocusEvent event )
{
System.err.println ( "@" + System.currentTimeMillis () + " AWT focus gained " + event.getComponent () );
}
public void focusLost ( final 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 ( final ContainerEvent event )
{
addFocusListenerToTree ( event.getChild () );
}
public void componentRemoved ( final ContainerEvent event )
{
removeFocusListenerFromTree ( event.getChild () );
}
}
private static AWTContainerListener _AWTContainerListener = new AWTContainerListener ();
static void addFocusListenerToTree ( final Component comp )
{
comp.addFocusListener ( _AWTFocusListener );
if ( comp instanceof Container )
{
final 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.
final int n = cont.getComponentCount ();
for ( int i = 0; i < n; i++ )
{
addFocusListenerToTree ( cont.getComponent ( i ) );
}
}
}
static void removeFocusListenerFromTree ( final Component comp )
{
// The exact opposite of addFocusListenerToTree.
comp.removeFocusListener ( _AWTFocusListener );
if ( comp instanceof Container )
{
final Container cont = (Container)comp;
cont.removeContainerListener ( _AWTContainerListener );
final 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 ( final String name )
{
final Logger logger = Logger.getLogger ( name );
logger.setLevel ( Level.FINEST );
final ConsoleHandler handler = new ConsoleHandler ();
handler.setLevel ( Level.FINEST );
logger.addHandler ( handler );
}
}