1 /*******************************************************************************
2 * Copyright (c) 2007 SAS Institute.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * SAS Institute - initial API and implementation
10 *******************************************************************************/
11 package org.simantics.utils.ui.internal.awt;
13 import java.awt.EventQueue;
15 import org.eclipse.swt.SWT;
16 import org.eclipse.swt.events.ControlAdapter;
17 import org.eclipse.swt.events.ControlEvent;
18 import org.eclipse.swt.events.DisposeEvent;
19 import org.eclipse.swt.events.DisposeListener;
20 import org.eclipse.swt.events.FocusEvent;
21 import org.eclipse.swt.events.FocusListener;
22 import org.eclipse.swt.events.KeyEvent;
23 import org.eclipse.swt.events.KeyListener;
24 import org.eclipse.swt.widgets.Composite;
25 import org.eclipse.swt.widgets.Display;
26 import org.eclipse.swt.widgets.Shell;
28 public class SwtFocusHandler implements FocusListener, KeyListener {
30 private Composite composite;
31 private final Display display;
32 private AwtFocusHandler awtHandler;
34 public SwtFocusHandler(Composite composite) {
35 assert composite != null;
36 assert Display.getCurrent() != null; // On SWT event thread
38 this.composite = composite;
39 display = composite.getDisplay();
40 composite.addFocusListener(this);
41 composite.addKeyListener(this);
44 public void setAwtHandler(AwtFocusHandler handler) {
45 assert handler != null;
46 assert awtHandler == null; // this method is meant to be called once
47 assert composite != null;
48 assert Display.getCurrent() != null; // On SWT event thread
52 // Dismiss Swing popups when the main window is moved. (It would be
53 // better to dismiss popups whenever the titlebar is clicked, but
54 // there does not seem to be a way.)
55 final ControlAdapter controlAdapter = new ControlAdapter() {
56 public void controlMoved(ControlEvent e) {
57 assert awtHandler != null;
58 awtHandler.postHidePopups();
61 final Shell shell = composite.getShell();
62 shell.addControlListener(controlAdapter);
64 // Cleanup listeners on dispose
65 composite.addDisposeListener(new DisposeListener() {
66 public void widgetDisposed(DisposeEvent e) {
67 // Remove listener from shell before nullifying awtHandler
68 shell.removeControlListener(controlAdapter);
76 void gainFocusNext() {
77 traverse(SWT.TRAVERSE_TAB_NEXT);
80 void gainFocusPrevious() {
81 traverse(SWT.TRAVERSE_TAB_PREVIOUS);
84 private void traverse(final int traversal) {
85 //assert composite != null;
86 if (composite == null)
89 // Tab from the containing SWT component while
90 // running on the SWT thread
91 Runnable r = new Runnable() {
93 composite.traverse(traversal);
99 // boolean hasFocus() {
100 // assert composite != null;
102 // // This will return true if the composite has focus, or if any
103 // // foreign (e.g. AWT) child of the composite has focus.
104 // if (display.isDisposed()) {
107 // final boolean[] result = new boolean[1];
108 // display.syncExec(new Runnable() {
109 // public void run() {
110 // result[0] = (!composite.isDisposed() &&
111 // (display.getFocusControl() == composite));
117 // ..................... Listener implementations
119 public void focusGained(FocusEvent e) {
120 assert awtHandler != null;
121 assert Display.getCurrent() != null; // On SWT event thread
123 // System.out.println("Gained: " + e.toString() + " (" + e.widget.getClass().getName() + ")");
124 EventQueue.invokeLater(new Runnable() {
126 // composite DisposeListener may have nullified this meanwhile!
128 if (awtHandler != null)
129 awtHandler.gainFocus();
134 public void focusLost(FocusEvent e) {
135 // System.out.println("Lost: " + e.toString() + " (" + e.widget.getClass().getName() + ")");
138 public void keyPressed(KeyEvent e) {
139 assert Display.getCurrent() != null; // On SWT event thread
141 // If the embedded swing root pane has no components to receive focus,
142 // then there will be cases where the parent SWT composite will keep
143 // focus. (For example, when tabbing into the root pane container).
144 // By default, in these cases, the focus is swallowed by the Composite
145 // and never escapes. This code allows tab and back-tab to do the
146 // proper traversal to other SWT components from the composite.
148 if (e.keyCode == SWT.TAB) {
149 // TODO: In some cases, this gobbles up all the tabs, even from AWT children. Find a more selective way.
150 /*if (e.stateMask == SWT.NONE) {
151 traverse(SWT.TRAVERSE_TAB_NEXT);
152 } else if (e.stateMask == SWT.SHIFT) {
153 traverse(SWT.TRAVERSE_TAB_PREVIOUS);
158 public void keyReleased(KeyEvent e) {