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