]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.utils.ui/src/org/simantics/utils/ui/internal/awt/SwtFocusHandler.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.utils.ui / src / org / simantics / utils / ui / internal / awt / SwtFocusHandler.java
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
7  *
8  * Contributors:
9  *     SAS Institute - initial API and implementation
10  *******************************************************************************/
11 package org.simantics.utils.ui.internal.awt;
12
13 import java.awt.EventQueue;
14
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;
27
28 public class SwtFocusHandler implements FocusListener, KeyListener {
29
30     private Composite       composite;
31     private final Display   display;
32     private AwtFocusHandler awtHandler;
33
34     public SwtFocusHandler(Composite composite) {
35         assert composite != null;
36         assert Display.getCurrent() != null;     // On SWT event thread
37         
38         this.composite = composite;
39         display = composite.getDisplay();
40         composite.addFocusListener(this);
41         composite.addKeyListener(this);
42     }
43
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        
49         
50         awtHandler = handler;
51         
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();
59             }
60         };
61         final Shell shell = composite.getShell();
62         shell.addControlListener(controlAdapter);
63         
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);
69                 awtHandler.dispose();
70                 awtHandler = null;
71                 composite = null;
72             }
73         });
74     }
75     
76     void gainFocusNext() {
77         traverse(SWT.TRAVERSE_TAB_NEXT);
78     }
79     
80     void gainFocusPrevious() {
81         traverse(SWT.TRAVERSE_TAB_PREVIOUS);
82     }
83     
84     private void traverse(final int traversal) {
85         //assert composite != null;
86         if (composite == null)
87             return;
88
89         // Tab from the containing SWT component while 
90         // running on the SWT thread
91         Runnable r = new Runnable() {
92             public void run() {
93                 composite.traverse(traversal);
94             }
95         };
96         display.asyncExec(r);
97     }
98
99 //    boolean hasFocus() {
100 //        assert composite != null;
101 //        
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()) {
105 //            return false;
106 //        }
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));
112 //            }
113 //        });
114 //        return result[0];
115 //    }
116
117     // ..................... Listener implementations
118     
119     public void focusGained(FocusEvent e) {
120         assert awtHandler != null;
121         assert Display.getCurrent() != null;     // On SWT event thread
122
123         // System.out.println("Gained: " + e.toString() + " (" + e.widget.getClass().getName() + ")");
124         EventQueue.invokeLater(new Runnable() {
125             public void run() {
126                 // composite DisposeListener may have nullified this meanwhile!
127                 // Not a bug.
128                 if (awtHandler != null)
129                     awtHandler.gainFocus();
130             }
131         });
132     }
133     
134     public void focusLost(FocusEvent e) {
135         // System.out.println("Lost: " + e.toString() + " (" + e.widget.getClass().getName() + ")");
136     }
137
138     public void keyPressed(KeyEvent e) {
139         assert Display.getCurrent() != null;     // On SWT event thread
140
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.
147         // TODO: other keys?
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);
154             }*/
155         }
156     }
157
158     public void keyReleased(KeyEvent e) {
159     }
160
161
162 }