Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [albireo-dev] Focus Management Test Cases

Hi Gordon,

> I've started to think about merging the two contributions for focus 
> management. It is a daunting task.

Yes, especially with the many actors involved: focus management on SWT side,
AWT focus manager, platform behaviour, the notions of "focus in window" etc.

I would take the bug list at http://wiki.eclipse.org/Albireo_SWT_AWT_bugs
and start with that. Also, I would concentrate on JDK 1.5 in the first time.
JDK 1.4 behaves the same regarding focus, but JDK 1.6 is different.

Can you please mark the focus-related hacks with isWin32() and isGtk()?
It's likely that a hack for Windows gets in the way on Gtk and vice versa,
because the underlying platforms are so different.

> The comments in IlvFocusDebugging and other ILOG files refer to a set of 
> problems labeled A through E. I assume the test case code that 
> demonstrates these problems includes proprietary ILOG code, so it can't 
> itself be contributed? Is there any chance we could create a set of 
> equivalent EPL test cases?

The test cases indeed involve some ILOG products and therefore are not
usable. But I can create a test code with pure Eclipse and Swing.

I'm committing the FocusDebugging class, so use can use that easily for
the analysis.

Bruno


Index: src/org/eclipse/albireo/core/SwingControl.java
===================================================================
RCS file: /cvsroot/technology/org.eclipse.albireo/org.eclipse.albireo.core/src/org/eclipse/albireo/core/SwingControl.java,v
retrieving revision 1.27
diff -c -3 -r1.27 SwingControl.java
*** src/org/eclipse/albireo/core/SwingControl.java	12 Feb 2008 14:51:30 -0000	1.27
--- src/org/eclipse/albireo/core/SwingControl.java	12 Feb 2008 15:09:03 -0000
***************
*** 26,31 ****
--- 26,32 ----
  import javax.swing.plaf.FontUIResource;
  
  import org.eclipse.albireo.internal.CleanResizeListener;
+ import org.eclipse.albireo.internal.FocusDebugging;
  import org.eclipse.albireo.internal.Platform;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.SWTException;
***************
*** 48,53 ****
--- 49,57 ----
      // and layout.
      private static final boolean verboseSizeLayout = false;
  
+     // Whether to print debugging information regarding focus events.
+     private static final boolean verboseFocusEvents = false;
+ 
      private Listener settingsListener = new Listener() {
          public void handleEvent(Event event) {
              handleSettingsChange();
***************
*** 155,160 ****
--- 159,167 ----
          AwtEnvironment.getInstance(display);
  
          frame = SWT_AWT.new_Frame(this);
+ 
+         if (verboseFocusEvents)
+             FocusDebugging.addFocusDebugListeners(this, frame);
      }
  
      protected void scheduleComponentCreation() {

================== src/org/eclipse/albireo/internal/FocusDebugging.java =======
/*******************************************************************************
 * 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;

/**
 * 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 three 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>
 * </ul>
 */
public class FocusDebugging {

  /**
   * Adds listeners for debugging all kinds of focus events.
   */
  public static void addFocusDebugListeners(org.eclipse.swt.widgets.Composite control,
                                            Container topLevelComponent) {
    control.addFocusListener(_SWTFocusListener);
    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 focus events on the top-level window on the AWT side.
   */
  private static class AWTWindowFocusListener implements WindowFocusListener {
    public void windowGainedFocus(WindowEvent event) {
      System.err.println("@"+System.currentTimeMillis()
                         +" AWT focus gained by window "+event.getWindow());
      KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
      System.err.println("owner1: "+kfm.getPermanentFocusOwner());
      System.err.println("owner2: "+kfm.getFocusOwner());
      System.err.println("owner3: "+event.getWindow().getFocusOwner());
    }
    public void windowLostFocus(WindowEvent event) {
      System.err.println("@"+System.currentTimeMillis()
                         +" AWT focus lost by window "+event.getWindow());
      KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
      System.err.println("owner1: "+kfm.getPermanentFocusOwner());
      System.err.println("owner2: "+kfm.getFocusOwner());
      System.err.println("owner3: "+event.getWindow().getFocusOwner());
    }
  }
  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));
    }
  }

}


Back to the top